MySQL 8.0.12+ 降序索引仅在版本≥8.0.12、SHOW CREATE TABLE 显示DESC、WHERE最左等值匹配、ORDER BY列序与方向逐列一致时才跳过filesort;否则严格失效。

ORDER BY 方向与索引定义不一致时,MySQL 8.0 的降序索引根本不会用于排序——它不是“自动适配”,而是“严格匹配”。只有当三者完全对齐:版本 ≥8.0.12、SHOW CREATE TABLE 显示 DESC、WHERE 提供最左等值条件、ORDER BY 列顺序和方向逐列一致,才能真正跳过 Using filesort。
确认降序索引是否真被物理创建
MySQL 8.0.11 及更早版本会静默忽略 DESC,建出来的仍是升序索引。不能只看建表语句写了没写 DESC,必须验证落地结果:
- 执行
SHOW CREATE TABLE your_table,输出中必须明确出现类似created_at DESC字样;如果只显示created_at,说明没生效 - 查系统表:
SELECT COLLATION FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_NAME = 'your_table' AND INDEX_NAME = 'idx_name' AND SEQ_IN_INDEX = 1,返回D才代表首列是降序(A是升序) -
PRIMARY KEY (id DESC)在 8.0.11 及之前会被强制转成升序,别信语法糖
ORDER BY 必须逐列与索引方向完全一致
方向错一位、少一位、多一位,整个排序能力就归零。MySQL 不会“部分复用”混合方向索引:
- 索引是
(status ASC, created_at DESC)→ 只加速ORDER BY status, created_at DESC,不支持ORDER BY created_at DESC单独出现 - 要优化
ORDER BY user_id DESC, updated_at ASC,必须显式建INDEX (user_id DESC, updated_at ASC);省略ASC虽语法合法,但可读性差,某些旧客户端解析可能出偏差 -
ORDER BY DATE(created_at) DESC这类函数表达式,无论索引怎么建,都强制走Using filesort
WHERE 条件必须压住最左前缀等值匹配
没有这个锚点,DESC 部分就是摆设。单列降序索引 + 范围查询基本无效:
-
WHERE status = 'done' ORDER BY created_at DESC→ 可用INDEX(status, created_at DESC) -
WHERE status IN ('done', 'pending') ORDER BY created_at DESC→ 8.0.19 及更早版本仍大概率触发Using filesort;8.0.20+ 才较稳定支持 -
WHERE updated_at > '2025-01-01' ORDER BY updated_at DESC→ B+ 树物理扫描方向与逻辑倒序冲突,极易退化为全索引扫描或全表扫 +filesort -
WHERE status = 'done' AND priority > 5 ORDER BY created_at DESC→priority > 5中断最左前缀连续性,created_at DESC失效
验证是否真跳过了 Using filesort
光看 EXPLAIN 的 key 字段命中索引名远远不够,关键盯三处:
-
Extra列不能出现Using filesort或Using temporary;理想状态是空,或仅Using index -
type应为ref、range或index,而非ALL -
rows值应明显小于总行数(比如百万级表降到几千),否则说明扫描范围过大,实际未发挥排序优势
最容易被忽略的是:单列 DESC 索引配范围查询,几乎从不生效;而联合索引中方向变化意味着一套新物理结构,INDEX(a ASC) 和 INDEX(a DESC) 在磁盘上是两套独立索引,空间和维护成本都要算进去。











