【问题标题】:Android: Why is Room so slow?Android:为什么 Room 这么慢?
【发布时间】:2021-08-07 01:17:55
【问题描述】:

我正在使用 Room 在 Kotlin 中开发一个简单的数据库过程,但我无法解释为什么这个过程如此缓慢,主要是在 Android Studio 模拟器上。

我正在处理的表是这样的:

@Entity(tableName = "folders_items_table", indices = arrayOf(Index(value = ["folder_name"]), Index(value = ["item_id"])))
data class FoldersItems(
        @PrimaryKey(autoGenerate = true)
        var uid: Long = 0L,

        @ColumnInfo(name = "folder_name")
        var folder_name: String = "",

        @ColumnInfo(name = "item_id")
        var item_id: String = ""

)

而我只是想做的是:检查组合文件夹/项目是否已经存在,插入一条新记录。如果没有,请忽略它。在模拟器上,插入 100 条记录最多需要 7-8 秒。在真实设备上,它要快得多,但仍然需要大约 3-4 秒,这对于仅 100 条记录来说是不可接受的。看起来“插入”查询特别慢。

这是我刚刚描述的过程(在协程内):

val vsmFoldersItems = FoldersItems()

items.forEach{

    val itmCk = database.checkFolderItem(item.folder_name, it)


    if (itmCk == 0L) {


        val newFolderItemHere = vsmFoldersItems.copy(
                                            folder_name = item.folder_name,
                                            item_id = it
        )
    
        database.insertFolderItems(newFolderItemHere)

    }
    
}

变量“items”是一个字符串数组。

这是上述函数的DAO定义:

@Query("SELECT uid FROM folders_items_table WHERE folder_name = :folder AND item_id = :item")
    fun checkFolderItem(folder: String, item: String): Long

@Insert
    suspend fun insertFolderItems(item: FoldersItems)

【问题讨论】:

  • 我认为您应该只在值列中使用create an unique index,然后只运行一批插入,而不是循环运行检查查询,然后对每个项目进行插入查询。
  • 谢谢@Pawel,我试过了,但事实是,由于这个过程是异步调用的,一旦插入查询尝试存储一个已经存在的值,它就会产生异常并且循环是破碎的。所以,我必须坚持我的简单查询检查......无论如何,谢谢!
  • 它有什么异常?如果我对“批量插入”不清楚,我的意思是修改(或添加新的)DAO 方法insertFolderItems 以使用OnConflictStrategy.IGNORE 消耗整个列表,并且您不会有任何循环。
  • 好点@Pawel,我没想到。我明天试试,然后报告。再次感谢您。
  • 是的@Pawel,解决了它!再次感谢!

标签: sqlite kotlin android-room dao


【解决方案1】:

将循环放在单个事务中应该会显着减少所花费的时间。

原因是每个事务(默认情况下每个对数据库进行更改的 SQL 语句)都会导致磁盘写入。因此,您的循环需要 100 次磁盘写入。

如果您在循环之前开始事务,然后在循环完成时设置事务成功,然后结束事务,则需要单个磁盘写入。

我不确定的是在使用挂起函数时如何执行此操作(对 Kotlin 不太熟悉)。

因此,我建议要么放弃暂停,要么在循环中使用另一个 Dao。

然后有类似的东西:-

val vsmFoldersItems = FoldersItems()
your_RoomDatabase.beginTransaction()
items.forEach{

    val itmCk = database.checkFolderItem(item.folder_name, it)


    if (itmCk == 0L) {


        val newFolderItemHere = vsmFoldersItems.copy(
                                            folder_name = item.folder_name,
                                            item_id = it
        )
    
        database.insertFolderItems(newFolderItemHere)

    }
    
}
your_RoomDatabase.setTransactionSuccessful() //<<<<<<< IF NOT set then ALL updates will be rolled back
your_RoomDatabase.endTransaction()

您不妨参考:-

您不妨特别参考runInTransaction

【讨论】:

  • 只需将该代码放在 DAO 类内部的抽象方法中(首先将其从接口转换为抽象类)并使用 @Transaction 注释该方法。然后应该在单个事务中执行整个方法。
  • 太棒了!谢谢你们!我最终使用了最新的 runInTransaction(),现在循环不到一秒。再次非常感谢!
  • 嘿,迈克,我只是在 2000 行中使用选择查询,但获取数据需要 6 到 8 秒?你能帮我吗?
  • @gulabpatel 你找到解决办法了吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-04-19
  • 2021-09-03
  • 2016-09-28
  • 2020-02-08
  • 2012-07-17
  • 2011-11-07
  • 2015-08-24
相关资源
最近更新 更多