Почему отдельные транзакции такие медленные? - PullRequest
0 голосов
/ 12 июня 2019

!!!ПОЛНАЯ РЕДАКТИРОВАТЬ !!!

Потому что мой вопрос не был четко определен и, следовательно, не решал проблему правильно.С помощью уже существующих ответов я провел еще несколько тестирований и отредактировал это.

Базовая линия / Задача

Храните 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
    }
}

Очистки в следующих частях кода удаляют более старые записи области.хранить не более 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 ]

1 голос
/ 13 июня 2019

Я не уверен, что есть «вопрос» как таковой, но я укажу пару вещей, которые означают, что вы не тестируете «время для написания N объектов», а «выполняете действия N раз, которые создаютN объектов ».Есть разница, и если это является частью проекта (а не просто проверкой вашего интереса), есть способы ускорить это.

  1. Для каждой записи вы открываете зановобазу данных (т.е. в storeInDb вы звоните Realm.getInstance) и затем закрываете ее.
  2. Вам не нужно требовать для вызова .refresh при открытии области.
  3. Вместо того, чтобы запрашивать наличие объекта, а затем вызывать .copyToRealm,просто позвоните .copyToRealmOrUpdate.
  4. Я не знаю, поможет ли это, или просто вызовет блокировку, но вы пытались использовать executeTransactionAsync вместо этого?

Как упомянуто в документах Realm, попробуйте и сделайтеуверен, что вы пакетные операции как можно больше.Если вы хотите добавить 1000 объектов, то добавьте 1000 объектов вместе.Столько, сколько стоит попытка сохранить абстрактное представление о базе данных, иногда при разработке может потребоваться понять концепцию «пакетных» операций.

1 голос
/ 12 июня 2019

повторная инициализация одного и того же экземпляра объекта замедлит ваш процесс, как вы это делали внутри testSize метода

Этот вопрос обсуждается здесь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...