MySQL 8.0.12+ 的 InnoDB 才真正支持 DESC 索引,需通过 SHOW CREATE TABLE 或 INFORMATION_SCHEMA.STATISTICS 验证是否生效;降序索引仅在等值查询+严格匹配索引列序和方向+覆盖索引时才能避免 Using filesort。

确认 MySQL 版本和存储引擎是否真正支持 DESC 索引
MySQL 8.0.12 之前(含 8.0.11)的 InnoDB 会静默忽略 DESC 关键字,建出来的仍是升序索引;MyISAM 则完全不支持物理降序存储。必须先验证:
执行 SELECT VERSION() 确保返回 ≥ 8.0.12;再运行 SHOW CREATE TABLE your_table,输出中必须明确出现类似 created_at DESC —— 如果只写 created_at,说明没生效;更准的方式是查系统表:SELECT COLLATION FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_NAME = 't' AND INDEX_NAME = 'idx',结果为 D 才代表降序已落地。
CREATE INDEX 里写 DESC 的实际生效条件
降序索引不是“写了就管用”,它只在三个条件同时满足时才能跳过 Using filesort:
– WHERE 最左列必须是等值匹配(= 或 IS NULL),不能是 IN、>、BETWEEN 等范围条件;
– ORDER BY 的列顺序和方向必须与索引定义逐列严格一致,包括显式写出 ASC(哪怕默认就是);
– SELECT 的所有列必须被该索引覆盖(即全部出现在索引定义中),否则回表后无法保证全局有序,仍会触发 Using filesort。
例如:要优化 ORDER BY user_id DESC, created_at ASC,必须建 INDEX (user_id DESC, created_at ASC);建 (user_id DESC, created_at DESC) 或 (user_id ASC, created_at DESC) 都完全无效。
单列降序索引 + 范围查询几乎必然失效
这是最常踩的坑:以为建了 INDEX (updated_at DESC),再写 WHERE updated_at > '2025-01-01' ORDER BY updated_at DESC 就能又过滤又排序——实际 B+ 树无法同时满足范围扫描和倒序读取的物理顺序要求,往往退化为全索引扫描或 fallback 到 backward scan,性能不升反降。
真正有效的做法是补一个高选择性等值条件:
– 改写为 WHERE status = 'done' AND updated_at > '2025-01-01' ORDER BY updated_at DESC;
– 对应索引应为 INDEX (status, updated_at DESC),把等值列放最左;
– 若只有范围条件,优化器大概率放弃使用该索引排序能力,直接走 filesort。
验证降序索引是否真正在工作
不能只看 EXPLAIN 的 key 字段是否命中索引名,关键盯紧三处:
– Extra 列必须不出现 Using filesort(有它就说明排序没下推);
– type 应为 ref 或 range,且 rows 远小于总行数;
– MySQL 8.0.20+ 可用 EXPLAIN FORMAT=TREE,直接看执行计划里有没有 filesort 节点。
另外注意:NULL 值在 DESC 索引中默认排在最前面(因 MySQL 视 NULL 为最小值),和 ASC 索引相反,可能引发业务语义偏差,需提前确认。



















