出乎意料的是Realm文件大小很大

时间:2017-09-14 20:59:50

标签: swift realm filesize

这个问题是关于使用两种不同的方法将对象插入到Realm中。我注意到第一种方法要快得多, 但与第二种方法相比,尺寸结果是巨大的。两种方法之间的差异正在推动 在for循环的内部和内部写入事务。

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

当我添加这样的对象时,Realm文件增长到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")
    }
}

当我添加这样的对象时,Realm文件只会增长到5.5MB:

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")
    }
}

要添加到域文件的我的类

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()
}

自动增量功能

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

有更好或更正确的方法吗?为什么在这些情况下我会得到不同的文件大小?

3 个答案:

答案 0 :(得分:8)

在单个事务中添加所有对象时的大文件大小是由于Realm的事务日志子系统与Realm的大型blob内存分配算法之间的不幸交互造成的。 Realm的内存布局算法要求文件大小至少是Realm文件中存储的最大单个Blob大小的8倍。事务日志条目(总结单个事务期间所做的修改)将作为Blob存储在Realm文件中。

在一个事务中添加40,000个对象时,最终会得到一个大小约为5MB的事务日志条目。这意味着文件的大小必须至少为40MB才能存储。 (我不太确定它的最终结果几乎是那个大小的两倍。可能是blob大小在某条线的某个位置被四舍五入到了...)

当你在40,000个事务中添加一个对象时,你仍然只有一个事务日志条目,这次只有大约一百个字节。发生这种情况是因为当Realm提交事务时,它会尝试在为新条目分配空间之前首先回收未使用的事务日志条目。由于Realm文件未在其他位置打开,因此可以在执行每个新提交时回收上一个条目。

realm/realm-core#2343跟踪改进Realm存储事务日志条目的方式,以避免您看到的重要位置。

现在我的建议是分割两种方法之间的差异,并为每个写入事务添加对象组。这将通过增加提交次数来折衷一点性能,但会通过减少您创建的最大事务日志条目的大小来减少内存布局算法的影响。从快速测试开始,提交每2,000个对象会导致文件大小约为4MB,而且比在单独的写入事务中添加每个对象要快得多。

答案 1 :(得分:1)

在大多数情况下,您应该尽量减少写入事务的数量。写事务具有显着的开销,因此如果为要添加到域的每个对象启动新的写事务,则代码将比使用单个写事务添加所有对象的速度慢得多。

根据我的经验,向域中添加多个元素的最佳方法是创建元素,将它们添加到数组中,然后使用单个写入事务将数组作为整体添加到Realm。

所以这就是你应该做的事情:

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)
}

关于大小问题,请参阅Realm文档的Limitations - File Size部分。我不是100%肯定问题的原因,但我会说这个问题是由写入事务中的代码编写引起的,并不需要在那里发生而且不应该在写入事务中发生。我想由于这个原因,Realm会创建很多对象的中间版本,因为释放预留的存储容量是一项非常昂贵的操作,所以在检查文件大小时它不会发生。

请记住,对象的创建并不需要在写入事务中发生。您只需要创建一个写事务来修改Realm中的持久数据(包括向Realm添加新对象,删除持久化对象和直接修改持久化对象)。

答案 2 :(得分:0)

谢谢大家。我找到了一种使用您的提示完成任务的优化方法。我只是批量编写.write,而不是在一次操作中发送所有内容。按照一些数据进行比较:

批量大小(对象)|文件大小(mb)

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

因此,我认为使用1000批次是这种情况的最佳尺寸/速度。

这是我用于此测试的代码。唯一改变的是1 ... XXX的互动。

    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)
        }
    }