为什么单笔交易这么慢?

时间:2019-06-12 12:39:31

标签: android realm

!!!完全编辑!!!

因为我的问题定义不明确,所以没有正确解决问题。在已经存在的答案的帮助下,我进行了更多测试并进行了编辑。

基准/任务

在两个“操作”中存储10.000个项目。跟踪领域的大小以及完成整个任务所需的时间。

这些项目具有以下结构:

class DbObject() : RealmObject() {
    @PrimaryKey
    @Index
    lateinit var id: String
        private set

    var data: ByteArray? = null
        private set

    var downloadedAt: Long = 0L

    var lastUsed: Long? = null

    constructor(
        id: String,
        data: ByteArray? = null,
        downloadedAt: Long
    ) : this() {
        this.id = id
        this.data = data
        this.downloadedAt = downloadedAt
        this.lastUsed = downloadedAt
    }
}

以下代码部分中的清理操作将删除较旧的Realm条目,以在该Realm中最多保留5000个项目。

测试

单次插入

分别插入每个项目,并在设定的周期(例如5次插入)后进行清理。

fun storeInDb(object: DbObject) {
    Realm.getInstance(DatabaseConfig.REALM_CONFIG).use { realmInstance ->
        realmInstance.refresh()
        realmInstance.executeTransaction {
            it.copyToRealmOrUpdate(object)
            cleanupTick = (cleanupTick + 1) % CLEANUP_CYCLE
            if (cleanupTick == 0) {
                cleanupDb(it)
            }
        }
    }
}

束插入

所有5000个项目都存储在一笔交易中。

fun storeListInDb(list: List<DbObject>) {
    Realm.getInstance(DatabaseConfig.REALM_CONFIG).use { realmInstance ->
        realmInstance.refresh()
        realmInstance.executeTransaction { realm ->
            list.forEach {
                realm.copyToRealmOrUpdate(it)
            }
        }
    }
}

分批/大块插入

这些项目存储在大约1000个项目的块中。

fun storeInDb(list: List<DbObject>) {
    Realm.getInstance(DatabaseConfig.REALM_CONFIG).use { realmInstance ->
        realmInstance.refresh()
        var index = 0
        while (list.lastIndex - index > 1000) {
            storeListInDb(realmInstance, list.subList(index, index + 1000))
            index += 1000
        }

        val rest = list.lastIndex - index
        if (rest > 0) {
            storeListInDb(realmInstance, list.subList(index, index + rest + 1))
        }

        realmInstance.executeTransaction {
            cleanupDb(realmInstance)
        }
    }
}

private fun storeListInDb(realmInstance: Realm, list: List<DbObject>) {
    realmInstance.executeTransaction { realm ->
        list.forEach {
            realm.copyToRealmOrUpdate(it)
        }
    }
}

测试结果

start: 480kb, end: 832kb, timeTaken: 370.622s    // 5000 individually (cleanup after 5 insertions)
start: 4608kb, end: 5120kb, timeTaken: 2.704s    // 5000 in one transaction (cleanup after whole list was stored)
start: 1664kb, end: 2048kb, timeTaken: 2.519s    // 5000 in chunks of 1000 (cleanUp after whole list was stored)

start:插入5000次后的领域大小 end:插入10000次后的领域大小

结论

大小:更多的较小事务将使Realm文件更小。

时间:大笔交易将减少时间(在大多数情况下)

问题

我现在的问题仍然是:为什么单笔交易这么慢(真该死)?对于5000件商品,它们的速度比批量交易要慢148倍。

2 个答案:

答案 0 :(得分:1)

重新初始化相同的对象实例将像在testSize方法中那样降低您的处理速度

此问题已讨论here

答案 1 :(得分:1)

我不确定是否存在这样的“问题”,但我要指出几件事,这意味着您没有像“做N次创建对象一样”来测试“写N个对象的时间” N个物体。两者之间是有区别的,并且如果这构成项目的一部分(而不仅仅是对您的兴趣的测试),那么有多种方法可以加快进度。

  1. 对于每次写入,您都将重新打开数据库(即在storeInDb中,您正在调用Realm.getInstance),然后关闭它。
  2. 打开领域时,您不需要呼叫.refresh
  3. 不是查询对象是否存在然后调用.copyToRealm,而是调用.copyToRealmOrUpdate
  4. 我不知道它是否有帮助,或者只是导致阻塞,但是您是否尝试过使用executeTransactionAsync呢?

如Realm文档中所述,请尝试确保尽可能多地批处理操作。如果要添加1000个对象,则将1000个对象加在一起。尽力保持数据库的抽象视图很有价值,但有时设计可能需要了解“批处理”操作的概念。