【问题标题】:Why is SQLITE taking forever on a simple count query?为什么 SQLITE 永远在一个简单的计数查询上?
【发布时间】:2020-06-06 12:06:24
【问题描述】:

我有一组 SQLITE 表,在磁盘上加起来最多 7 GB。我正在查询的特定表 (FQ) 大约有 50 列和 300 万行。

我正在从 sqlite3 交互式 shell (sqlite3.exe) 进行查询。我正在运行的查询是:“从 FQ 中选择计数(日期);”。大约 300 万行需要 10 多分钟 来计算。第一次之后,它似乎被缓存了,结果几乎是即时的。我在一台 8 GB RAM 的 Windows 10 PC 上运行,没有其他任何东西在运行。

日期是两个主键之一(日期和 ID)。有 360 个唯一日期和大约 8 到 10k 个 ID,并且该表对于每个日期/ID 组合都有一个条目。

以下是我已经做过的一些事情:

  1. 我在整个表上有一个覆盖索引。
  2. 我已经在这个数据库上运行了 ANALYZE。
  3. 当我执行“EXPLAIN QUERY PLAN”时,它说它正在使用覆盖索引进行表扫描(按预期进行计数)。

简单地扫描一个包含 300 万行的表怎么会花费这么长时间?

[编辑:我应该澄清我对其他计数方式不感兴趣 - 我希望扫描不必那么慢(它也很慢,例如,使用 sum()+"分组")]

[更新:今天我尝试了另外两件事——首先我尝试使用“WITHOUT ROWID”,结果都相似。然后我完全删除了所有表的索引。现在,几百万行的计数在 4 秒内完成。现在所有索引都消失了,数据库文件自然更小(2 GB 对 7 GB),但这不能解释 10 分钟到 4 秒的差异!是什么让覆盖索引减慢了表扫描速度?是否存在扫描索引较慢的地方,如果是,为什么 SQLITE 不只扫描原始表本身?]

【问题讨论】:

  • select count(*) from fq 需要多长时间?
  • 第一次没有缓存任何东西可能是其中的一部分,是的。
  • @GordonLinoff,使用 * 会使它花费更长甚至更长的时间 - 很难准确判断,因为缓存难以控制。
  • @Shawn,足够公平,没有缓存会减慢它的速度,但我可以将整个数据库文件(7 GB)复制到 USB 硬盘上,而不是计算 300 万一个表的行。即使没有任何缓存,我也不认为需要那么长时间(或者是吗?)
  • @jwcoder 。 . . count(*) 中的 * 实际上使查询 更快 而不是更慢。数据库引擎知道它可以使用任何索引(或数据页)来计算行数。

标签: sql database sqlite database-tuning


【解决方案1】:

我终于找到了问题所在。在数据库上运行 VACUUM 命令解决了这个问题。我已经运行 .dbinfo 来确认 page_size 乘以页数加起来大约是文件大小。再加上我没有从数据库中删除任何内容(只是插入),这让我认为我不需要清理(或整理碎片)。

但是,vacuum 所做的重组似乎也对计数查询的速度产生了巨大的影响(正如我在其他地方看到的那样,现在可以在几毫秒内完成)。

【讨论】:

  • 很高兴知道。感谢您分享解决方案并将您的问题标记为已回答。我没想到vacuum 会是解决方案。非常感谢。
  • @zedfoxus - 没问题,我从这里的很多答案中受益,这是我能做的最少的事情! :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多