MySQL 8.0+支持降序索引,但ORDER BY混合方向排序生效需满足三条件:索引列顺序与查询一致、每列升降序严格匹配、WHERE满足最左前缀;否则仍触发Using filesort。

ORDER BY 混合方向排序能跳过 Using filesort,但前提是索引定义与查询的列顺序、升降序方向逐列严格一致,且 WHERE 条件满足最左前缀。
为什么MySQL 5.7的联合索引对ORDER BY a DESC, b ASC完全无效
因为它的索引底层只按升序物理存储,哪怕你写 INDEX (a DESC, b ASC),SHOW CREATE TABLE 一看就发现 DESC 和 ASC 全被忽略,实际建出来是 (a, b) 全升序。B+ 树叶子节点无法同时满足“a 从大到小、b 从小到大”的扫描路径,优化器只能放弃索引排序,强制走 Using filesort。
CREATE INDEX 必须显式写出每个字段的方向
MySQL 8.0 不会默认补全方向,没写的列一律按 ASC 处理。
- 要加速
ORDER BY status ASC, created_at DESC,必须建CREATE INDEX idx_status_created ON orders (status ASC, created_at DESC) - 建成
(status, created_at DESC)(省略ASC)等价于(status ASC, created_at DESC),没问题 - 但建
(status DESC, created_at DESC)就只对ORDER BY status DESC, created_at DESC有效,对ASC/DESC混合场景完全无用 - 主键中用
DESC要特别注意:8.0.11 及更早版本会直接忽略,8.0.12+ 才真正支持
验证降序索引是否真在工作,只看EXPLAIN的三个字段
别光盯着 key 是否显示索引名——那只是说明用了这个索引做查找,不等于跳过了排序。
-
Extra字段里**不能出现**Using filesort—— 这是最硬的指标 -
type应为range或ref,而不是ALL(全表扫描)或index(全索引扫描) -
rows值应明显小于表总行数,说明走了索引范围扫描,而非全量读取后排序 - MySQL 8.0.20+ 可用
EXPLAIN FORMAT=TREE,直接看到执行计划里有没有filesort节点
最容易被忽略的失效场景
不是语法写错,而是语义没对齐。
-
WHERE created_at > '2025-01-01'却指望INDEX (status ASC, created_at DESC)做排序 —— 不行,created_at不是最左列,索引根本没法按created_at DESC有序扫描 -
WHERE status IN ('paid', 'shipped') ORDER BY created_at DESC—— 部分版本会退化为范围扫描,created_at DESC的排序能力可能减弱 -
SELECT *配合INDEX (status, created_at DESC)—— 若表含大字段(如TEXT),仍需回表,而回表后的结果集无法保证全局有序,MySQL 可能悄悄加回Using filesort -
ORDER BY DATE(created_at) DESC—— 含函数表达式,任何索引都无效,包括降序索引
真正起效的时刻,是 WHERE 锁定最左等值列 + ORDER BY 方向与索引定义逐列咬合 + 查询列尽量落在索引内。这三个条件缺一不可,少一个,Using filesort 就还在后台等着。



















