我使用Room作为SQLite的抽象层。阅读此page后,我发现我们可以同时插入多个对象。目前我使用For循环来插入对象,即每个For循环迭代中的一个对象。我目前知道的两种插入方式是:
使用For循环并一次插入一个对象
@Insert(onConflict = OnConflictStrategy.REPLACE)
public void addActivity(Person person);
插入数组或对象列表。
@Insert(onConflict = OnConflictStrategy.REPLACE)
public void insertUsers(Person ... people);
当我编码对象的插入时,我不知道第二种插入方式。现在我想知道两种方式之间的速度是否有明显差异,以便我可以更改我的代码以提高我的应用程序的性能。
答案 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) }
这花了不到一秒钟。
这里的重点是专门使用DAO Iterable<>
方法的@Insert
版本,正如@iDemigod所说,它使用Iterable<>
的{{1}}版本。
该函数的主体在@iDemigod的答案中,并且对所有插入使用单个准备好的语句。
将SQL解析为一条语句非常昂贵,使用一条语句会为整个插入批处理创建一个事务,这可以帮助解决其他问题(我在数据库上有一个可观察的EntityInsertionAdapter
,被通知了12,000次)在插入期间...的表现糟糕)。
答案 1 :(得分:0)
引擎盖室内生成的类正在使用EntityInsertionAdapter
来处理这种特殊情况。有两种方法,我们需要检查:
这个用于插入单个实体
public final long insertAndReturnId(T entity) {
final SupportSQLiteStatement stmt = acquire();
try {
bind(stmt, entity);
return stmt.executeInsert();
} finally {
release(stmt);
}
}
虽然这个用于插入实体数组
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
包裹的循环中插入,那么就没有变化。