mysql 8.0.12+ 引入倒序索引是为解决降序查询被迫 filesort 或反向扫描的性能硬伤;此前版本b+树仅升序存储,即使写desc也静默忽略,优化器只能低效倒扫或全排序。

DESC 索引不是“自动提速”,它只在严格匹配时跳过 Using filesort——不满足条件时,建了也白建,甚至拖慢写入。
为什么 ORDER BY col DESC 在 8.0 之前必须走 filesort?
MySQL 5.7 及更早版本的 B+ 树索引只按升序物理存储。即使你写 INDEX (col DESC),实际建出来仍是 col ASC。当执行 ORDER BY col DESC 时,优化器只能从叶子节点末尾往前“倒着扫”,I/O 跳页多、缓存局部性差;多列混合方向(如 ORDER BY a DESC, b ASC)则完全无法对齐,必然触发 Using filesort。
CREATE INDEX ... (col DESC) 在 8.0.12+ 才真正生效
MySQL 8.0.11 及之前会静默忽略 DESC,建出的仍是升序索引。验证是否真支持,必须:
- 执行
SHOW CREATE TABLE t,输出中明确出现col DESC - 查系统表:
SELECT COLLATION FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_NAME = 't' AND INDEX_NAME = 'idx',结果为D表示降序,A就是升序(哪怕 DDL 里写了DESC) - 主键中写
PRIMARY KEY (id DESC)在 8.0.11 及之前会被强制转成升序,别信语法糖
WHERE + ORDER BY + SELECT 必须三者严丝合缝
缺一不可,否则 Extra: Using filesort 一定出现:
-
WHERE必须提供索引最左列的等值匹配(=或IS NULL),例如索引是(status, created_at DESC),就得写WHERE status = 'done';用WHERE status IN (...)、status > 10或直接省略WHERE,排序能力就断了 -
ORDER BY的列顺序和方向必须与索引定义逐列完全一致:索引是(a ASC, b DESC),只认ORDER BY a, b DESC;写成ORDER BY a ASC, b DESC通常仍可识别,但ORDER BY a DESC, b DESC就彻底不匹配 -
SELECT列最好被索引覆盖,避免回表;尤其别用SELECT *——如果含TEXT字段,MySQL 更倾向全字段排序,容易触发Using disk sort
建了 INDEX (col DESC) 却更慢的常见原因
这不是 bug,是设计代价被忽略的结果:
- 空间翻倍:
INDEX (a ASC)和INDEX (a DESC)是两套独立物理结构,InnoDB 不复用;联合索引中混合方向(如(a ASC, b DESC))也不能替代(a DESC, b ASC) - 维护开销增加:每次
INSERT/UPDATE都要按反向规则编码键值,对高写入表有轻微影响 - 优化器误选:当统计信息不准,或查询带函数(如
ORDER BY DATE(created_at) DESC),降序索引直接失效,且无法 fallback 到升序索引,只能全表扫 +filesort - 单列降序索引 + 范围查询 = 大概率白建:比如
WHERE updated_at > '2025-01-01' ORDER BY updated_at DESC配INDEX (updated_at DESC),B+ 树物理扫描方向与范围查询冲突,优化器常退化为全索引扫描
Using filesort 就不会消失。











