尽管缺少列但仍使用覆盖指数


8

我有以下查询,使用MariaDB 10 / InnoDB:

SELECT id, sender_id, receiver_id, thread_id, date_created, content 
FROM user_message 
WHERE thread_id = 12345 
  AND placeholder = FALSE
ORDER BY date_created DESC 
LIMIT 20

该查询根据给定的条件获取消息,并按创建日期排序。

我的覆盖范围超过(thread_id, date_created)

当运行EXPLAIN时,使用正确的索引,尽管查询使用的是语句中间不在索引中的列,但我得到的输出为“在哪里使用”。我可以将任何值用于“占位符= x”,并且结果相同。

如果我将排序更改为使用另一列,则EXPLAIN正确指示“在哪里使用。使用文件排序”。

我正在抓头。有人可以阐明这一点吗?我希望看到的是,由于覆盖列无法完全使用,因此需要额外的文件排序。

Answers:


8

案例A
查询:

WHERE thread_id = 12345 
  AND placeholder = FALSE
ORDER BY some_column DESC 
LIMIT 20

指数:

(thread_id, date_created)

计划:

Index is used
Using Where
Using filesort

没问题吧?如果使用索引(部分匹配WHERE条件),我们仍然需要排序操作来对结果进行排序some_column(不在索引中)。我们还需要进行额外的检查(在何处使用)以仅保留与第二个条件匹配的行。好。


案例B(问题)
查询:

WHERE thread_id = 12345 
  AND placeholder = FALSE
ORDER BY date_created DESC 
LIMIT 20

指数:

(thread_id, date_created)

计划:

Index is used
Using Where
-- no "Using filesort"

那么,为什么这里不需要排序呢?因为索引足以按查询所需进行排序。当然AND placeholder = FALSE,存在索引未涵盖的额外条件()的其他问题。

好的,但是我们这里真的不需要排序。索引可以为我们提供与第一个条件(WHERE thread_id = 12345)匹配并且以想要的顺序输出的结果。我们唯一需要做的额外检查(以及计划的工作)是按照索引提供的顺序从表中获取行,并检查第二个条件,直到获得20个匹配项。这就是“在哪里使用”的意思。

我们可能会在前20行(非常好又快)或前100行(还是很可能足够快)或前1000000(可能非常非常慢)中获得20场比赛,或者从19行中获得20场比赛。即使从索引中读取了所有匹配的行,该表也是如此(在大表上确实非常慢)。这一切都取决于数据的分布。


案例C(甚至更好的计划)
查询:

WHERE thread_id = 12345 
  AND placeholder = FALSE
ORDER BY date_created DESC 
LIMIT 20

指数:

(placeholder, thread_id, date_created)

计划:

Index is used
-- no "Using Where"
-- no "Using filesort"

现在,我们的索引匹配条件和排序依据。该计划非常简单:从索引中获取前* 20个匹配项,然后从表中读取相应的行。不需要额外的检查(不需要“在哪里使用”),也不需要排序(不需要“使用文件排序”)。

first *:从后向后读取索引时的前20个(如我们所知ORDER BY .. DESC),但这不是问题。B树索引可以以几乎相同的性能向前和向后读取。


7
  • 使用索引表示“ 覆盖索引” - 所有的任何地方SELECT任何地方的一个指标。因此,您没有“覆盖”索引。为查询创建覆盖索引(提及过多列)是不实际的。
  • 在哪里使用 -主要是噪音。
  • 使用文件排序-查询需要排序,但它可能在RAM或临时表中。并且可能有多种(例如GROUP BY x ORDER BY b
  • 这两种方法都只能查看20行;任何其他索引将需要触摸更多行,可能需要触摸整个表:

    INDEX(thread_id, placeholder, date_created)
    INDEX(placeholder, thread_id, date_created)
    
  • 不,在对索引中的列进行排序时,复合索引的组件的基数无关紧要。

我的食谱解释了如何在给定的情况下得出最佳索引SELECT


谢谢你的菜谱-非常好的表。
汤姆(Tom)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.