We’ve been successfully using Realm for an iOS app for some time now and it’s been working perfectly. But the performance of our latest development version has suddenly nose-dived. There were several changes that might be related:
We changed from using the pod version Realm to SPM
Xcode bumped from 13.1 to 13.2
We updated to the latest Realm iOS SDK (11.9.0)
…but this might be unrelated.
Operations that took a fraction of a second are now taking many seconds. I’ll use the simplest possible case as an example:
I made a fresh build of the app on an iPad (so the dbase is empty)
I created about 350 records - it took roughly 10 seconds (where previously it would be a tiny fraction of that time)
Reading records remained as fast as expected
I then removed about 300 records - it took about 8 seconds (and previously would be almost instant)
Record removal is the most alarming - this is done in one step with no intermediate processing and no background activity. I can’t think of any reason for it becoming to alarmingly slow - the app is almost unusable.
We tried a release build to rule out the possibility that the debug build was somehow slowed by using SPM, but it made no perceptible difference. I also used a profiler on the code and it spends all its time in the bowels of Realm - there doesn’t seem to be any other app activity.
I’ve searched for any similar experiences, but found nothing so far. Any suggestions for testing/fixing the issue?
Ok - we’ve worked it out. I’ll explain what we did for anyone else that might benefit from it.
Firstly, our app hadn’t been pushing Realm very hard until recently. We jumped from transactions dealing with dozens of records up to hundreds/thousands fairly recently. This brought a lurking issue into the light.
To fix the issue, we first tried stepping back to an earlier version of Realm. While this worked about 3x faster than the most recent version, it was still vastly slower than it should have been.
I studied the code and realised there might be another issue. The app partially evolved from a prototype, and some of the weaker code still persisted. Early handed data in an ad-hoc fashion and had no undo. I implemented a transactional system for all database interaction in order to implement undo and, while I did update a lot of code dealing with Realm, I missed a critical flaw.
Every Realm write (record write/remove) was still done as an individual and serial transaction, e.g. if we removed 300 records, it was done as 300 serial Realm transactions. And that was the sole cause of the problem. If we wrote all the changes from an app transaction as a single Realm transaction, performance leapt up.
The takeaway is that completing a Realm transaction is probably far slower than most changes you might make within the transaction. Our app was constantly waiting for each transaction to complete in order to start the next. Writing everything in one transaction was a night and day change. Kind-of obvious when you see it, but worth being aware of for anyone seeing a similar problem.