【发布时间】:2017-06-23 08:25:22
【问题描述】:
我有一个包含大约 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-20s 下降到 1.8-2.8s。然后我删除了预写,它进一步下降到 1.3-2.7 秒。所以这个问题仍然很明显,尽管它确实好很多了。
【问题讨论】:
-
我将首先确定并发插入对应用程序与查询的影响。换句话说,禁用新数据的插入,并测量相同的选择语句运行多长时间。此外,了解一次插入多少行以及该操作是否在事务中运行也会很有帮助。
标签: android sqlite android-sqlite sqlcipher