案例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树索引可以以几乎相同的性能向前和向后读取。