2

我有一个包含大约 500K 行的表。该表在“状态”列上有一个索引。所以我运行以下解释命令:

EXPLAIN QUERY PLAN SELECT * FROM my_table WHERE status = 'ACTIVE'

结果是可预测的“解释”......

SEARCH TABLE my_table USING INDEX IDX_my_table_status (status=?) (~10 rows)

在表中添加了许多额外的行之后,我调用了“分析”。之后,查询似乎慢了很多,所以我重新运行了我的解释,现在看到以下内容:

SCAN TABLE my_table (~6033 rows)

我注意到的第一件事是,这两个行估计都相差甚远。最大的担忧是,一旦运行 ANALYZE,索引似乎就被跳过了。我尝试了 REINDEX - 无济于事。我可以取回索引的唯一方法是删除它们,然后重新创建它们。有人见过这个吗?这是一个错误吗?任何想法我做错了什么?我已经在多个数据库上尝试过这个,我看到了相同的结果。这是在我的 PC、MAC 和 iPhone/iPad 上——结果都是一样的。

4

2 回答 2

1

当 SQLite 使用索引从表中获取行时,它必须首先读取索引页,然后读取包含一个或多个匹配记录的表的所有页。如果匹配的记录很多,则几乎所有表的页面都可能包含一个,因此通过索引将需要读取更多页面。

但是,SQLite 的查询计划器没有关于索引或表中记录大小的信息,因此它的估计可能是错误的。

收集的信息ANALYZE存储在sqlite_stat1和 maysqlite_stat3中。请显示有关您的桌子的信息。
如果该信息不能反映您的数据的真实分布,您可以尝试再次运行,或者只是从表中ANALYZE删除该信息。sqlite_stat*

如果ORDER BY在索引字段上使用,则可以强制遍历索引。(INDEXED BY正如其文档所述,用于调整查询性能。)

如果您不需要选择表的所有字段,您可以通过在这些查询的字段上创建索引来加速特定查询,以便您拥有覆盖索引

于 2012-10-18T06:43:11.187 回答
0

查询执行计划避免在像“status”这样的低基数列上使用现有索引并不少见,它可能只有几个不同的值。通过扫描 db 表来执行查找通常更快。(一些 DBA 建议永远不要索引低基数列。)

然而,基于解释计划中变化很大的行数,我猜测SQLite 的“分析”在使用 InnoDB 存储引擎时与 MySQL 的“分析”类似。MySQL 的“分析”对表数据进行一组随机潜水以确定行数、索引基数等。由于随机潜水,每次“分析”运行后统计信息可能会有所不同,并导致不同的查询执行计划。低基数列更容易受到不正确的统计数据的影响,例如,随机跳水可能表明表中的大多数行都处于“活动”状态,这使得表扫描比使用索引更有效. (我不是 SQLite 专家,所以如果我对“分析”有预感,请有人插话

您可以尝试使用“indexed by”(请参阅​​ http://www.sqlite.org/lang_indexedby.html)在查询中测试索引的使用,尽管强制使用索引通常是最后的手段。不同的 RDBMS 对低基数问题有不同的解决方案,例如分区、使用位图索引等。我建议研究特定于 SQLite 的解决方案来对低基数列进行查询/索引)。

于 2012-10-18T05:28:27.273 回答