Sqlite 安卓:为什么房间这么慢?

Sqlite 安卓:为什么房间这么慢?,sqlite,kotlin,android-room,dao,Sqlite,Kotlin,Android Room,Dao,我正在Kotlin using Room中开发一个简单的数据库过程,我无法解释为什么这个过程如此缓慢,主要是在Android Studio emulator上 我正在处理的表格如下: @Entity(tableName = "folders_items_table", indices = arrayOf(Index(value = ["folder_name"]), Index(value = ["item_id"]))) data c

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

我正在处理的表格如下:

@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 = ""

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

下面是我刚才描述的过程(在协同程序中):

变量“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)


将循环放置在单个事务中可以显著减少所需的时间

原因是每个事务(默认情况下,每个对数据库进行更改的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()
val vsmFoldersItems=FoldersItems()
您的_RoomDatabase.beginTransaction()
项目。forEach{
val itmCk=database.checkFolderItem(item.folder_name,it)
如果(itmCk==0L){
val newFolderItemHere=vsmfolderItems.copy(
folder\u name=item.folder\u name,
item_id=it
)
database.insertFolderItems(newFolderItemHere)
}
}

your_RoomDatabase.setTransactionSuccessful()//我认为您应该在值列之外运行一个批处理插入,而不是循环并运行检查查询,然后对每个项目执行插入查询。谢谢@Pawel,我尝试过了,但事实是,由于此过程是异步调用的,一旦insert查询尝试存储已经存在的值,它就会发生异常,循环就会中断。所以,我必须坚持我的简单查询检查。。。无论如何谢谢你!有什么例外吗?如果我对“批插入”不清楚,我想修改(或添加新的)DAO方法
insertFolderItems
,使用
OnConflictStrategy来使用整个列表。忽略
,你就不会有任何循环。好的一点@Pawel,我没有想到这一点。我明天试试,然后报告。再次感谢你。是的@Pawel,它修好了!再次感谢!只需将该代码放在DAO类内的抽象方法中(首先将其从接口转换为抽象类),并用@Transaction注释该方法即可。整个方法应该在一个事务中执行。太棒了!谢谢你们!我使用最新的runInTransaction()进行endedup,现在循环只需不到一秒钟的时间。再次非常感谢!
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()