SQLite在最近的插入时选择非常慢

时间:2017-06-23 08:25:23

标签: android sqlite android-sqlite sqlcipher

我有一张大约有700万行的表格。我平均每秒插入一行到数据库中。当我这样做时,我注意到对数据库运行一个简单的SELECT需要花费相当长的时间(多达15秒),例如类似的东西:

SELECT * FROM table WHERE rowid > 7100000

此选择通常不返回任何数据行,因为有时在此特定表中未插入任何数据。即使我正在写的表实际上甚至没有在我正在阅读的表中插入行,它也经常发生。

这个想法是有两个独立的过程,一个是添加数据,另一个是尝试获取尚未读取的所有新数据。但是读取端连接到UI,任何明显的延迟都是无法忍受的,更不用说15秒了。这是在Android下运行的,并且UI线程也不喜欢被阻止这么长时间,并且它正在造成严重破坏。

我最初的想法可能是插入需要更新指标,因为我最初在不同的字段(时间字段)上有索引。这似乎至少部分得到了证实,因为如果我使用只有几行的数据库,则每个选择在几毫秒内完成。但是当我重新创建表只有rowid作为主键时,它实际上变慢了。我希望在将rowid作为主键进行比较时,在末尾插入一个新行总是会导致非常快速的读取。

我已尝试启用提前写入日志,但似乎SQLCipher不支持此功能,至少不是直接支持,因为它不符合android.database.sqlite.SQLiteDatabase的最新API。即使在postKey钩子中使用“PRAGMA journal_mode = WAL”也没有任何区别。

这里发生了什么?如何加快选择?

更新:我试图摆脱sqlcipher,只是使用普通的sqlite来判断这是否是一个因素。我使用sqlcipher_export导出到纯文本数据库,然后使用默认的android.database.sqlite.SQLCipher。延迟时间从10-20秒降至1.8-2.8秒。然后我删除了预写,它进一步下降到1.3-2.7s。所以问题仍然存在,尽管它确实变得更好。

1 个答案:

答案 0 :(得分:0)

SQLite最终是基于文件的,并且没有可移植的机制来与另一个进程通信,哪个部分文件已经更改。因此,当一个进程写入某些内容时,所有其他进程在下次访问数据库文件时必须删除它们的缓存。

如果可能,请修改您的体系结构,使代码的两个部分位于同一进程中并共享相同的数据库连接。 (对于多个线程,这需要锁定,但SQLite无论如何都没有太大的并发性。)

或者,将新数据写入单独的数据库,然后让UI应用程序将其移动到自己的数据库中。

我不知道为什么SQLCipher会慢得多(它不太可能是解密的CPU开销)。