mysql 8.0降序索引仅在where最左等值匹配、order by方向与索引逐列严格一致、select列被索引覆盖时才跳过filesort;否则无效甚至更慢,需通过explain验证extra字段是否消失。

它只在三个条件同时满足时跳过 Using filesort,否则不生效,甚至更慢——这不是“自动加速”,而是“精准匹配才省事”。
降序索引生效的硬性条件缺一不可
建了 INDEX (status, created_at DESC),不代表 ORDER BY created_at DESC 就能用上。必须同时满足:
-
WHERE必须提供索引最左列的等值匹配(=或IS NULL),比如WHERE status = 'done';用WHERE status IN (...)、status > 10或直接省略WHERE,排序能力就断了 -
ORDER BY的列顺序和方向必须和索引定义逐列完全一致:索引是(a ASC, b DESC),就只认ORDER BY a, b DESC;写成ORDER BY a ASC, b DESC通常仍可识别,但ORDER BY a DESC, b DESC就彻底不匹配 -
SELECT列最好被索引覆盖,避免回表;尤其别用SELECT *——如果含TEXT字段,MySQL 8.0 更倾向全字段排序,容易触发Using disk sort
为什么匹配成功就能跳过 filesort?
本质不是“更快”,而是“少做一件事”:
- MySQL 5.7 对
ORDER BY x DESC只能靠升序索引 + 后向扫描(从 B+ 树末尾往前读),I/O 跳页多、缓存局部性差 - MySQL 8.0 的降序索引把键值真实按降序存进 B+ 树,优化器能从前向后顺序读取,物理顺序 = 逻辑顺序,无需额外排序步骤
- 效果体现在
EXPLAIN的Extra字段消失Using filesort,且type是index或range,rows显著减少
建了降序索引反而变慢的常见原因
这不是 bug,是设计代价被忽略的结果:
- 空间翻倍:
INDEX (a ASC)和INDEX (a DESC)是两套独立物理结构,InnoDB 不复用;联合索引中混合方向(如(a ASC, b DESC))也不能替代(a DESC, b ASC) - 维护开销增加:每次
INSERT/UPDATE都要按反向规则编码键值,对高写入表有轻微影响 - 优化器误选:当统计信息不准,或查询带函数(如
ORDER BY DATE(created_at) DESC),降序索引直接失效,且无法 fallback 到升序索引,只能全表扫 +filesort
怎么确认降序索引真正在工作?
光看 EXPLAIN 的 key 字段不够,关键盯三处:
-
Extra列不能出现Using filesort或Using temporary -
type应为ref、range或index,而非ALL -
rows值应明显小于表总行数(比如从百万级降到几千) - MySQL 8.0.20+ 可用
EXPLAIN FORMAT=TREE,直接看执行计划里有没有filesort节点
最容易被忽略的是:单列降序索引配合范围查询基本无效,比如 WHERE updated_at > '2025-01-01' ORDER BY updated_at DESC ——B+ 树对单列降序索引做范围扫描时,物理存储顺序和扫描方向冲突,往往退化为全索引扫描。











