为什么 MySQL 对此查询执行文件排序?

Why is MySQL performing a filesort on this query?

为什么 MySQL 对此查询执行文件排序?我只是期待 Using where:

SELECT * FROM active_campaign_days
WHERE ad_unit_id=1
AND day='2017-12-10'
ORDER BY bid DESC, budget DESC, campaign_id ASC

(ad_unit_id, day, bid, budget, campaign_id) 上的索引 - 数据库根据 EXPLAIN 使用此索引。

在这个特定的结果集中,bidbudget 对于所有行都是相同的。 (ad_unit_id, campaign_id) 是独一无二的。

解释:

id  select_type     table   type    possible_keys   key     key_len     ref     rows    Extra   
1   SIMPLE  active_campaign_days    ref     ad_unit_id,ad_unit_id_2     ad_unit_id_2    7   const,const     5   Using where; Using filesort

让我们剖析查询..

  1. WHERE ad_unit_id=1 AND day='2017-12-10' 需要一个以 ad_unit_idday 开头的索引(顺序不限)。这将提供最佳过滤。

  2. 如果可行,可以将所有 ORDER BY 添加到 INDEX 中,这样就可以避免对数据进行排序。但是 ORDER BY bid DESC, budget DESC, campaign_id ASC 有一个问题。请注意,混合了 DESCASC。 MySQL 只能在一个方向上扫描一个索引。这意味着全部必须是 ASC 或全部必须是 DESC。 (请参阅下面的注释)因此,INDEX(ad_unit, day, bid, budget, campaign_id) 没有您想要的那么有用。

  3. 如果优化器可以通过第 2 步,则在 SELECT 中添加 任何地方 提到的任何其他列(即所有 *),那么索引就会变成 "covering"。这提供了不同种类的性能提升——通过在索引中完成所有工作,而不必触及 'data'.

注意:从 8.0 版开始,MySQL 将在索引声明中遵循 DESC。因此,您可以说 INDEX(ad_unit, day, bid DESC, budget DESC, campaign_id ASC),优化器可以使用它 而无需在上面的第 2 项中排序 。 (8.0 之前,DESC 在索引声明中被允许,但被忽略。)

解决方法?它会改变输出的顺序,但您可能会接受所有列 ASC(或所有 DESC)?

与此同时,INDEX(ad_unit_id, day) 就是所有值得拥有的东西。