mysql 8.0.12+ innodb才真正支持降序索引,仅当order by方向与索引逐列严格一致、where满足最左前缀等值匹配、无函数表达式时,才能跳过using filesort;否则无效甚至白建。

能,但只在 ORDER BY 方向与索引定义逐列严格一致、WHERE 条件满足最左前缀、且无函数表达式时,才真正跳过 Using filesort。其他情况建了也白建。
确认 MySQL 版本和存储引擎是否真正支持 DESC 索引
MySQL 8.0.12+ 的 InnoDB 才真正把 DESC 写进物理索引;8.0.11 及更早版本会静默忽略,建出来的还是升序索引。
- 执行
SHOW CREATE TABLE table_name,输出里必须明确出现col_name DESC才算生效 - 查系统表:
SELECT COLLATION FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_NAME = 't' AND INDEX_NAME = 'idx',结果为D表示降序,A就是升序(哪怕你写了DESC) - 主键中写
PRIMARY KEY (id DESC)在 8.0.11 及之前会被强制转成升序,别信语法糖
ORDER BY 与索引方向必须逐列完全匹配
方向错一位、少一位、多一位,整个排序逻辑就失效,必然触发 Using filesort —— 不是“部分生效”,而是彻底不走索引排序。
-
INDEX (a DESC, b ASC)只加速ORDER BY a DESC, b ASC;对ORDER BY a DESC, b DESC或ORDER BY a DESC单独使用都无效 -
INDEX (a ASC, b DESC)和ORDER BY a DESC, b ASC完全不匹配,B+ 树物理结构不兼容,无法复用 - 联合索引中任意列方向变化,都意味着一套新索引,
INDEX (c1 ASC)和INDEX (c1 DESC)在磁盘上是两套独立结构
单列降序索引 + 范围查询 = 大概率白建
这是最常踩的坑:以为 INDEX (updated_at DESC) 配上 WHERE updated_at > '2025-01-01' ORDER BY updated_at DESC 就能又过滤又排序——实际往往退化为全索引扫描。
- B+ 树对单列降序索引做范围扫描时,物理存储顺序与扫描方向冲突,优化器倾向放弃索引排序
- 真正有效的组合是:高选择性等值条件 + 降序字段,例如
WHERE status = 'done' AND updated_at > '2025-01-01' ORDER BY updated_at DESC - 对应索引必须是
INDEX (status, updated_at DESC),让status构成最左前缀,后续才能复用updated_at DESC排序
验证降序索引是否真正在工作
光看 EXPLAIN 的 key 字段命中不够,关键盯三处:Extra、type、rows。
-
Extra出现Using filesort→ 没走成索引排序,无论你建了多少个DESC索引 -
type是ref或range,且rows显著小于总行数(比如百万级表降到几千)→ 基本确认走了索引扫描层排序 - MySQL 8.0.20+ 可用
EXPLAIN FORMAT=TREE,直接看执行计划里有没有filesort节点 - 注意:
Backward index scan是 5.7 的 fallback 行为,不是 8.0 降序索引生效标志
降序索引不是给单字段倒排准备的,它是为「等值过滤 + 精确方向排序」这个组合服务的;单独建 INDEX (col DESC),90% 场景既浪费空间又拖慢写入,还掩盖了真正的问题——比如漏掉高选择性 WHERE 条件或用了隐式类型转换。











