Unexpectedly large Realm file size

This question is about using two different ways to insert objects into Realm. I noticed that the first method is much faster, but the size result is huge compared to the second method. The difference between the two approaches is to move write the transaction outside vs inside the for loop.

 // Create realm file let realm = try! Realm(fileURL: banco_url!) 

When I add such objects, the Realm file grows to 75.5MB:

 try! realm.write { for i in 1...40000 { let new_realm_obj = realm_obj(value: ["id" : incrementID(), "a": "123", "b": 12.12, "c": 66, "d": 13.13, "e": 0.6, "f": "01100110", "g": DateTime, "h": 3]) realm.add(new_realm_obj) print("๐Ÿ”น \(i) Added") } } 

When I add such objects, the Realm file grows to 5.5 MB:

 for i in 1...40000 { let new_realm_obj = realm_obj(value: ["id" : incrementID(), "a": "123", "b": 12.12, "c": 66, "d": 13.13, "e": 0.6, "f": "01100110", "g": DateTime, "h": 3]) try! realm.write { realm.add(new_realm_obj) print("๐Ÿ”น \(i) Added") } } 

My class to add to the area file

 class realm_obj: Object { dynamic var id = Int() dynamic var a = "" dynamic var b = 0.0 dynamic var c = Int8() dynamic var d = 0.0 dynamic var e = 0.0 dynamic var f = "" dynamic var g = Date() dynamic var h = Int8() } 

Auto zoom function

 func incrementID() -> Int { let realm = try! Realm(fileURL: banco_url!) return (realm.objects(realm_obj.self).max(ofProperty: "id") as Int? ?? 0) + 1 } 

Is there a better or right way to do this? Why in these cases do I get such different file sizes?

+4
source share
3 answers

The large file size when adding all the objects in one transaction is due to the unsuccessful interaction between the Realm transaction log subsystem and the Realm memory allocation algorithm for large blocks. The real-time memory composition algorithm requires that the file size be at least 8x the size of the largest single blob stored in the Realm file. Transaction log entries that summarize changes made during a single transaction are saved as drops in the Realm file.

When you add 40,000 objects to a single transaction, you get a single transaction log entry of about 5 MB in size. This means that the file size must be at least 40 MB in order to save it. (I'm not quite sure how it ends up about twice as large as this size. Perhaps the blob size is rounded to a power of two somewhere along the line ...)

When you add one object to 40,000 transactions, you still enter one transaction log entry, only this time for a hundred bytes in size. This is because when Realm completes a transaction, it tries to restore the unused transaction log entries first before allocating space for new entries. Since the Realm file is not opened elsewhere, the previous record can be restored when each new commit is executed.

realm / realm-core # 2343 tracks the improvement in how Realm stores transaction log entries to avoid the significant overall view that you see.

Now my suggestion was to split the difference between the two approaches and add groups of objects to the write transaction. This will decrease performance by increasing the number of commits, but it will reduce the impact of the memory layout algorithm by reducing the size of the largest transaction log entry that you create. From a quick test, when each 2000 objects are executed, the file size is about 4 MB, and much faster than adding each object to a separate write transaction.

+7
source

In most cases, you should try to minimize the number of write transactions. Therefore, if you start a new write transaction for each object that you want to add to the area, your code will be significantly slower than if you added all objects with a single write transaction.

In my experience, the best way to add multiple elements to an area is to create the elements, add them to the array, and then add the whole array to Realm with a single write transaction.

So here is what you should do:

 var objects = [realmObj]() for i in 1...40000{ let newRealmObj = realmObj(value: ["id" : incrementID(), "a": "123","b": 12.12,"c": 66,"d": 13.13,"e": 0.6,"f": "01100110","g": DateTime, "h": 3]) objects.append(newRealmObj) } try! realm.write { realm.add(objects) } 

For the size problem, see the Limitations - File Size section of the Realm documentation. I am not 100% sure about the cause of the problem, but I would say that the problem is writing code inside a write transaction that should not happen there and should not happen inside a write transaction. I suppose because of this, Realm creates many intermediate versions of your objects, and since releasing the reserved storage capacity is quite an expensive operation, this does not happen at the time of checking the file size.

Keep in mind that objects must not be created inside a write transaction. You only need to create a write transaction to modify the stored data in Realm (which includes adding new objects to Realm, deleting persistent objects, and directly modifying stored objects).

+1
source

Thanks to everyone. I found an optimized way to complete the task using your tips. I just did .write in packages instead of sending all the content in one operation. Follow some data for comparison:

Lot Size (Objects) | File size (mb)

10.000 = 23.1mb
5.000 = 11.5mb
2.500 = 5.8mb
1.250 = 4.2mb
625 = 3.7 MB
300 = 3.7 MB
100 = 3.1 MB
50 = 3.1mb
10 = 3.4mb
5 = 3.1mb

Thus, in my humble opinion, working with lots of 1000 is the best size / speed for this case.

Here is the code I used for this test. The only thing that changed was for 1 ... XXX internment.

  let realm = try! Realm(fileURL: banco_url!) var objects = [realm_obj]() var ids = incrementID() while (ids < 40000) { for i in 1...5{ let new_realm_obj = realm_obj(value: ["id" : ids, "a": "123", "b": 12.12, "c": 66, "d": 13.13, "e": 0.6, "f": "01100110", "g": someDateTime, "h": 3]) objects.append(new_realm_obj) ids += 1 } try! realm.write { realm.add(objects) } } 
0
source

All Articles