MySQL 8.0.12+ 才真正支持物理倒序索引,需同时满足版本≥8.0.12、建表语法含DESC、WHERE等值锚定最左前缀、ORDER BY方向与索引逐列严格一致,否则DESC无效且EXPLAIN显示Using filesort。

MySQL 8.0.12+ 才真正支持物理倒序索引,且必须满足「版本够、语法对、WHERE锚定、ORDER BY方向逐列一致」四者同时成立,否则 DESC 只是摆设,EXPLAIN 里照样出现 Using filesort。
确认 MySQL 版本和索引是否物理落地
8.0.11 及更早版本会静默忽略 DESC,建出来的仍是升序索引。别只信 CREATE INDEX 语句没报错——它真不报错,但也没用。
- 执行
SELECT VERSION(),确保返回值 ≥8.0.12 - 运行
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是升序) -
MyISAM引擎完全不支持倒序索引,哪怕版本够也不行
ORDER BY 方向必须与索引定义逐列严格一致
MySQL 不会“凑合用”或“部分复用”方向不匹配的索引。错一位、少一位、多一位,整个排序逻辑就失效。
- 要优化
ORDER BY user_id DESC, updated_at ASC,必须建INDEX (user_id DESC, updated_at ASC) -
INDEX (user_id DESC, updated_at DESC)对上述查询完全无效 -
INDEX (user_id ASC, updated_at DESC)同样不匹配——首列方向已错 - 显式写出
ASC更安全:INDEX (status ASC, created_at DESC)比INDEX (status, created_at DESC)可读性更强,也避免旧客户端解析歧义
WHERE 条件必须构成最左前缀等值匹配
倒序索引的排序能力不是天生的,它依赖前面的等值条件“锚定”扫描起点。没有这个锚点,DESC 部分就形同虚设。
- 有效组合:
WHERE status = 'done' ORDER BY created_at DESC→ 对应索引(status, created_at DESC) - 低效甚至无效:
WHERE created_at > '2025-01-01' ORDER BY created_at DESC→ 单列范围 + 倒序排序,B+ 树物理顺序冲突,极易退化为全索引扫描 -
WHERE status IN ('done', 'pending') ORDER BY created_at DESC:8.0.19 及更早版本大概率仍触发Using filesort;8.0.20+ 才较稳定支持 -
WHERE status = 'done' AND priority > 5 ORDER BY created_at DESC:priority > 5中断最左前缀连续性,created_at DESC失效
验证倒序索引是否真正在工作
不能只看 EXPLAIN 的 key 字段是否命中索引名——那只是说明用了这个索引做查找,不等于排序复用了它。
- 关键盯三处:
Extra列必须不出现Using filesort,type应为ref或range,rows应显著小于总行数 - 8.0.20+ 可用
EXPLAIN FORMAT=TREE,直接看执行计划里有没有filesort节点 - 函数表达式必破索引:
ORDER BY DATE(created_at) DESC无论索引怎么建,都强制走Using filesort - 单列
DESC索引在多数场景下是负优化:浪费空间、拖慢写入,还让人误以为问题已解决
最容易被忽略的是:倒序索引不是给「单字段倒排」准备的,它是为「高选择性等值条件 + 精确方向排序列」这个组合服务的。建之前先跑一遍 SELECT COUNT(DISTINCT status) FROM t 确认选择性——基数太低(比如只有 3 个值),再严格的索引也救不了性能。


















