Android会议室。哪种插入方法会更快?

时间:2018-05-17 06:26:48

标签: android sqlite sql-insert android-room android-architecture-components

我使用Room作为SQLite的抽象层。阅读此page后,我发现我们可以同时插入多个对象。目前我使用For循环来插入对象,即每个For循环迭代中的一个对象。我目前知道的两种插入方式是:

  1. 使用For循环并一次插入一个对象

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

  2. 插入数组或对象列表。

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

  3. 当我编码对象的插入时,我不知道第二种插入方式。现在我想知道两种方式之间的速度是否有明显差异,以便我可以更改我的代码以提高我的应用程序的性能。

2 个答案:

答案 0 :(得分:3)

按照OP在他们的问题的评论中的要求,以下是我(为了清楚起见,作为回答)对性能进行检查的内容:

在此之前,一一插入对象:

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

在华为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) }

这花了不到一秒钟。

这里的重点是专门使用DA​​O Iterable<>方法的@Insert版本,正如@iDemigod所说,它使用Iterable<>的{​​{1}}版本。

该函数的主体在@iDemigod的答案中,并且对所有插入使用单个准备好的语句。

将SQL解析为一条语句非常昂贵,使用一条语句会为整个插入批处理创建一个事务,这可以帮助解决其他问题(我在数据库上有一个可观察的EntityInsertionAdapter,被通知了12,000次)在插入期间...的表现糟糕)。

答案 1 :(得分:0)

引擎盖室内生成的类正在使用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);
        }
    }
    
  3. 您可以看到内部与您的内部几乎相同 - stmt.executeInsert();被调用一次或在循环中。使用我能想到的insertUsers方法的唯一性能变化是更改通知,只有在插入所有用户时才会发生一次。但是如果你已经在用@Transaction包裹的循环中插入,那么就没有变化。