Android Room.Какой способ вставки будет быстрее? - PullRequest
0 голосов
/ 17 мая 2018

Я использую Room как слой абстракции над SQLite.Прочитав эту страницу , я обнаружил, что мы можем вставлять несколько объектов одновременно.В настоящее время я использую цикл For для вставки объектов, то есть по одному объекту в каждой итерации цикла For.Два способа вставки, о которых я знаю в настоящее время:

  1. Использование цикла For и вставка каждого объекта по одному

    @Insert(onConflict = OnConflictStrategy.REPLACE) public void addActivity(Person person);

  2. Вставка массива или списка объектов.

    @Insert(onConflict = OnConflictStrategy.REPLACE) public void insertUsers(Person ... people);

Когда я кодировал вставку объектов, я не зналвторого способа вставки.Теперь я хочу знать, есть ли заметная разница в скоростях между этими двумя способами, чтобы я мог изменить свой код, чтобы повысить производительность своего приложения.

Ответы [ 2 ]

0 голосов
/ 26 июня 2018

В соответствии с просьбой ОП в комментарии к их вопросу вот (для ясности в качестве ответа), что я сделал для проверки производительности:

Перед тем, как вставлять объекты один за другим:

@Dao
abstract class MyDao {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    abstract fun insert(items: MyObject): Long
    // ...
}

Код синхронизации:

val response = backend.downloadItems() // download from server
val items = response.getData() // this is a List<MyObject>
if (items != null) {
    for (i in items) {
        myDao.persist(s)
    }
}

Это заняло минуту на Huawei P10 +.

Я изменил это на:

@Dao
abstract class MyDao {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    abstract fun insert(items: Iterable<MyObject>)
    // ...
}

Код синхронизации:

val response = backend.downloadItems() // download from server
val items = response.getData() // this is a List<MyObject>
response.getData()?.let { myDao.insert(it) }

Это заняло меньше секунды.

Смысл здесь в том, чтобы конкретно использовать Iterable<> версию метода DAO @Insert, который, как сказал @iDemigod,использует Iterable<> версию EntityInsertionAdapter.

. Тело указанной функции находится в ответе @ iDemigod и использует один подготовленный оператор для всех вставок.

Анализ SQLв оператор стоит дорого, и использование оператора создает транзакцию для всего пакета вставки, что может помочь решить другие проблемы (у меня было заметное значение LiveData<> в базе данных, которое было уведомлено 12 раз при вставке ... производительность была ужасно ).

0 голосов
/ 17 мая 2018

Под капотом Классы, сгенерированные в комнате, используют EntityInsertionAdapter для этой конкретной ситуации.И есть два метода, нам нужно проверить:

  1. Этот используется для вставки одного объекта

     public final long insertAndReturnId(T entity) {
        final SupportSQLiteStatement stmt = acquire();
        try {
            bind(stmt, entity);
            return stmt.executeInsert();
        } finally {
            release(stmt);
        }
    }
    
  2. В то время как этотиспользуется для вставки массива сущностей

    public final void insert(Iterable<T> entities) {
        final SupportSQLiteStatement stmt = acquire();
        try {
            for (T entity : entities) {
                bind(stmt, entity);
                stmt.executeInsert();
            }
        } finally {
            release(stmt);
        }
    }
    

Поскольку вы можете видеть, что внутреннее устройство в значительной степени совпадает с вашим - stmt.executeInsert(); вызывается один раз или в цикле.Единственное изменение производительности с использованием метода insertUsers, о котором я могу думать, - это уведомление об изменении, которое произойдет только один раз, когда будут вставлены все пользователи.Но если вы уже делаете вставку в цикл, обернутый @Transaction, тогда никаких изменений не будет.

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