Skip to main content

2 posts tagged with "Performance"

Performance and optimization

View All Tags

My openEHR CDR was 15x slower than the competition... or so I thought

· 2 min read
Borut Jures
Author of ArcEHR

A week ago I noticed my openEHR Clinical Data Repository (CDR) felt a bit sluggish. Naturally, I benchmarked it against EHRbase.

The results were brutal:

❌ My CDR: 15 ms to commit a composition

⚡ EHRbase: 1 ms

Humble pie served. I immediately went down the profiling rabbit hole to figure out where my architecture was bleeding performance. After two days of profiling, I accepted that the best I could do with my CDR was 6 times slower than EHRbase.

Fast forward to today: I started benchmarking read performance. To do that, I needed the UIDs of the inserted EHRs and compositions. But EHRbase wasn't returning them in the response body.

That’s when the dominoes started falling:

  • I was expecting openEHR REST API 1.1.0 responses, but EHRbase follows 1.0.2 (which returns UIDs in the ETag response header).
  • While investigating responses, I noticed something strange: EHRbase was also returning errors on every single EHR creation.
  • The issue? EHRbase expects an EHR_STATUS with PERSON, whereas the latest spec example uses PARTY_SELF.

The plot twist: That 1 ms benchmark wasn't committing compositions at lightning speed. It was just reporting creation errors in record time. The contributions were never actually processed. 😂

Once I fixed the payload and reran the benchmarks properly:

🐢 EHRbase real speed: 9.62 ms

⚡ My optimized CDR: 4.43 ms

The first test involves creating 100 EHRs, each with 1000 compositions. I’m using an 885-line Vital signs composition to make the test realistic:

Total mm:ssper composition
EHRbase16:029,62 ms
ArcEHR7:224,43 ms

The second test is querying the compositions using all seven different ways to use the GET COMPOSITION endpoints (700k queries):

Total mm:ssper composition
EHRbase30:5518,56 ms
ArcEHR4:312,72 ms

I’m running this on my 5-year-old Apple M1 Pro with 16 GB RAM, while simultaneously running 3 IDEs and Docker.

Moral of the story: Always check your HTTP status codes before you start questioning your entire architecture.

How Source Code Access Cut openEHR CDR Query Times to O(1)

· 2 min read
Borut Jures
Author of ArcEHR

Judging openEHR CDR performance is tough. You can stress-test by inserting millions of compositions and benchmarking queries. But even if it feels fast, how do you know it can’t be faster?

When I finished my openEHR CDR, it was hitting 15ms per committed composition. Humanly fast—but I wanted to test the limits.

Because ArcEHR gives customers full source code access—and uses an open-source database written in the same language—I ran the IntelliJ IDEA profiler across the entire stack.

The Profiler's Trail​

  1. The flame graph pointed to high execution time inside CreateCompositionHandler:

Check for duplicate UID

  1. Drill-down revealed the culprit: lookupByUid(), an innocent check to see if a UID already exists.

lookupByUID method

  1. Following the query into the database engine exposed why the SQL query was lagging.

Database engine SQL equals condition evaluator

The Fix​

The UID lookup index was using an LSM Tree. Switching to a Hash Index brought lookup time down to O(1)—ensuring lookups stay instant no matter how large the CDR grows.

Conclusion​

Why source code matters: Without visibility into the full stack, a bottleneck like this remains invisible. Source code access turns black-box performance limits into solvable engineering problems.

Have you encountered performance bottlenecks or scaling issues with your openEHR CDR? How are you profiling your health data architecture?