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?