尽管在应用了限制的索引列上进行过滤,为什么查询优化器会显示扫描的行数 = 匹配行总数?

Why would the query optimiser show rows scanned = total number of matched rows despite filtering on an indexed column with a limit applied?

我有一个具有以下结构的 table:

table 大约有 25000 行。 由于我在列 field1 上有一个索引,因此在 explain 查询 运行 时,我看到的扫描行较少。然而,我的问题是,在使用 limit (没有偏移量)之后,为什么它会在使用索引列而不是限制(在下面的示例中为 10)进行过滤的情况下扫描每个匹配的行?

以下是我 运行 的查询及其相应的结果:





这是我的问题:

  1. Query1 上,即使有索引列(在其上进行过滤)并应用了限制,为什么优化器会考虑扫描每个匹配的结果?确实有 1287 行 field1 = 'val9'。此外,我还注意到,如果我尝试将 field1 过滤为不存在的值,explain returns rows=1!例如: explain SELECT id, field1 from exam_tests where field1 = 'val11' order by field1 limit 10; 此处,field1 列没有值为 val11 的行。在这种情况下,我得到以下结果:
  2. Query3 仅仅因为我们添加了一个 order by indexed column,查询优化器如何能够在不扫描整个 table(the过滤列,field2,没有索引)?

EXPLAIN中的Rows

  • 是一个估计,通常是一个非常粗略的估计;和
  • 通常不考虑LIMIT

查询 1 -- 查询仅使用索引的 BTree 执行。 (线索:“使用索引”)。它可能只触及了 10 行。 (解释中没有线索)

查询 2 -- 完整 table 扫描(线索:AllNulls)。它读取了所有行,但可能只传送了一小部分行(线索:过滤 10.00%——又是粗略估计)

查询 3 -- 嗯...它选择了错误的 [我的意见] 方式来执行查询;它决定使用索引,但没有意识到它可能必须遍历整个 table 才能找到 10 行。 INDEX(field2, field1)这样的顺序最合适。

查询 4 ​​--(也许您打错了?ORDER BY 是不必要的,因为输出的所有行都具有相同的值。)

其他帮手:

  • 如果您想确切知道触摸了多少行,请执行以下操作:

    FLUSH STATUS;
    SELECT ... ;
    SHOW SESSION STATUS LIKE 'Handler%';
    
  • EXPLAIN FORMAT=JSON SELECT ...

  • “优化器跟踪”。

  • 慢日志记录“检查的行”。

  • Index Cookbook(它包括 'Handler' 和优化器跟踪提示。)

也许以下内容可以解决您的最后一个问题。如果 table 中没有匹配的行,仍然需要进行探测才能发现该事实。这会将一些 actual 行计数增加 1,包括 0 到 1。同样,如果只有 6 行匹配 WHERE(并且少于 LIMIT) , 它将 'examine' 7 行意识到是时候停止了。