为什么 SQLITE 会永远处理一个简单的计数查询?
Why is SQLITE taking forever on a simple count query?
我有一组 SQLITE table,磁盘上总计 7 GB。我正在查询的特定 table (FQ) 大约有 50 列和 300 万行。
我正在从 sqlite3 交互式查询 shell (sqlite3.exe)。我 运行ning 的查询是:"select count(Date) from FQ;"。大约 300 万行需要 10 多分钟 才能计算出来。第一次之后,它似乎被缓存了,结果几乎是即时的。我 运行正在 Windows 10 PC 上使用 8 GB RAM,没有其他 运行ning。
日期是两个主键之一(日期和 ID)。有 360 个唯一日期和 ~8-10k 个 ID,table 每个 date/ID 组合都有一个条目。
以下是我已经做过的一些事情:
- 我对整个table有一个覆盖索引。
- 我对这个数据库进行了 运行 分析。
- 当我执行 "EXPLAIN QUERY PLAN" 时,它说它正在使用覆盖索引执行 table 扫描(正如预期的那样进行计数)。
300 万行的 table 的简单扫描怎么会花这么长时间?
[编辑:我应该澄清一下,我对其他计数方式不感兴趣——我希望扫描不必这么慢(它也很慢,例如,使用 sum() +"group by")]
[更新:今天我尝试了另外两件事 - 首先我尝试使用 "WITHOUT ROWID" 并且两种方式的结果都相似。然后我完全删除了所有 table 的索引。现在几百万行的计数在 4 秒 内完成。既然所有索引都消失了,数据库文件自然更小(2 GB 对 7 GB),但这不应该解释 10 分钟到 4 秒的差异!是什么让覆盖索引减慢 table 扫描?有没有什么地方扫描索引比较慢,如果是这样,为什么 SQLITE 不只扫描原始 table 本身?]
终于找到问题了。 运行 数据库上的 VACUUM 命令解决了这个问题。我有 运行 .dbinfo 来确认 page_size 乘以页数加起来大约等于文件大小。再加上我没有从数据库中删除任何内容(仅插入)这一事实,让我假设我不需要清理(或整理碎片)。
但看起来 vacuum 所做的重组也对计数查询的速度产生了巨大的影响(正如我在其他地方看到的那样,现在以毫秒为单位完成)。
我有一组 SQLITE table,磁盘上总计 7 GB。我正在查询的特定 table (FQ) 大约有 50 列和 300 万行。
我正在从 sqlite3 交互式查询 shell (sqlite3.exe)。我 运行ning 的查询是:"select count(Date) from FQ;"。大约 300 万行需要 10 多分钟 才能计算出来。第一次之后,它似乎被缓存了,结果几乎是即时的。我 运行正在 Windows 10 PC 上使用 8 GB RAM,没有其他 运行ning。
日期是两个主键之一(日期和 ID)。有 360 个唯一日期和 ~8-10k 个 ID,table 每个 date/ID 组合都有一个条目。
以下是我已经做过的一些事情:
- 我对整个table有一个覆盖索引。
- 我对这个数据库进行了 运行 分析。
- 当我执行 "EXPLAIN QUERY PLAN" 时,它说它正在使用覆盖索引执行 table 扫描(正如预期的那样进行计数)。
300 万行的 table 的简单扫描怎么会花这么长时间?
[编辑:我应该澄清一下,我对其他计数方式不感兴趣——我希望扫描不必这么慢(它也很慢,例如,使用 sum() +"group by")]
[更新:今天我尝试了另外两件事 - 首先我尝试使用 "WITHOUT ROWID" 并且两种方式的结果都相似。然后我完全删除了所有 table 的索引。现在几百万行的计数在 4 秒 内完成。既然所有索引都消失了,数据库文件自然更小(2 GB 对 7 GB),但这不应该解释 10 分钟到 4 秒的差异!是什么让覆盖索引减慢 table 扫描?有没有什么地方扫描索引比较慢,如果是这样,为什么 SQLITE 不只扫描原始 table 本身?]
终于找到问题了。 运行 数据库上的 VACUUM 命令解决了这个问题。我有 运行 .dbinfo 来确认 page_size 乘以页数加起来大约等于文件大小。再加上我没有从数据库中删除任何内容(仅插入)这一事实,让我假设我不需要清理(或整理碎片)。
但看起来 vacuum 所做的重组也对计数查询的速度产生了巨大的影响(正如我在其他地方看到的那样,现在以毫秒为单位完成)。