mysql 8.0.12+ 的 innodb 表中 create index 的 desc 才被真正识别,此前版本会静默忽略;仅当 order by 列顺序与方向完全匹配索引定义、where 等值覆盖最左前缀、且无函数包裹时,才能跳过 filesort。

CREATE INDEX 里写 DESC 真的会被识别吗
会,但仅限 MySQL 8.0.12+ 的 InnoDB 表;更早版本(包括 8.0.11 及之前)会静默忽略 DESC,建出来仍是升序索引。执行 SHOW CREATE TABLE 能直接验证:如果输出里明确写了 a DESC,说明生效了;如果只显示 a,那它没被存下来。
哪些 ORDER BY 场景能真正跳过 filesort
必须同时满足三个硬条件,缺一不可:
-
ORDER BY的列顺序、方向与索引定义逐列完全一致(比如索引是(status, created_at DESC),那只有ORDER BY status, created_at DESC才行;ORDER BY created_at DESC单独用,或ORDER BY status DESC, created_at DESC都不行) -
WHERE条件覆盖索引最左前缀,且必须是等值匹配(=或IN列表,不能是>、BETWEEN等范围条件) -
ORDER BY字段不能包裹函数(如DATE(created_at) DESC),否则索引失效
为什么 EXPLAIN 看到 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% 的场景都浪费空间还拖慢写入。











