mysql 8.0.12+ 的 innodb 才真正支持 desc 索引,此前版本静默忽略;联合索引方向须与 order by 逐列严格一致,否则触发 filesort;单列降序索引配合范围查询常无效,需等值条件+联合索引。

CREATE INDEX 里写 DESC 到底有没有用
只有 MySQL 8.0.12+ 的 InnoDB 表才真正识别 DESC;8.0.11 及更早版本会静默忽略,建出来的还是升序索引。验证方式很简单:SHOW CREATE TABLE table_name 输出里如果明确写了 a DESC,说明生效了;如果只显示 a,那它根本没存下来。也可以查系统表:SELECT COLLATION FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_NAME = 't' AND INDEX_NAME = 'idx',结果为 D 才代表降序。
ORDER BY a DESC, b ASC 必须配对应方向的联合索引
MySQL 8.0 支持每列独立指定方向,但方向组合必须和 ORDER BY 逐列严格一致——少一个 ASC、多一个 DESC 都不行。比如要优化 ORDER BY user_id DESC, created_at ASC,就得建 INDEX (user_id DESC, created_at ASC)。
-
INDEX (user_id DESC, created_at DESC)对ORDER BY user_id DESC, created_at ASC完全无效 -
INDEX (user_id ASC, created_at DESC)同样不匹配,因为首列方向已错 - 方向不一致不是“部分生效”,而是整个排序逻辑无法下推,必然触发
Using filesort
为什么 key 字段命中了,却还是 Using filesort
key 字段只说明用了哪个索引做数据查找,不保证排序复用。关键看 Extra 字段:
- 出现
Using filesort→ 排序没走索引,哪怕key显示命中了带DESC的索引 - 没出现
Using filesort,且type是ref或range,rows远小于总行数 → 基本确认排序已下推到索引扫描层 - MySQL 8.0.20+ 可用
EXPLAIN FORMAT=TREE,直接看执行计划里有没有filesort节点
单列降序索引 + WHERE 范围条件 = 白建
这是最常踩的坑:建了 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,再配联合索引(status, updated_at DESC) - 降序索引不是给单字段倒排准备的,它是为「等值过滤 + 精确方向排序」这个组合服务的
- 单独建
DESC索引,90% 的场景都浪费空间还拖慢写入
降序索引在 InnoDB 中实际存储为反向键值(比如字符串按字节逆序编码),这意味着 INDEX (a ASC) 和 INDEX (a DESC) 物理上完全不兼容,得各建一套——空间翻倍、写入开销也翻倍。别急着加 DESC,先盯紧 WHERE 条件是否压住了最左前缀、ORDER BY 是否裸用函数、以及 EXPLAIN 里 Extra 真实状态。











