能跳过Using filesort,但仅当WHERE最左列等值匹配、ORDER BY方向与索引逐列严格一致、SELECT列被索引覆盖三者同时满足;缺一不可。

ORDER BY 降序查询能跳过 Using filesort,但仅当三个条件**同时满足**:WHERE 最左列等值匹配、ORDER BY 方向与索引逐列严格一致、SELECT 列被索引覆盖。缺一不可,否则建了也白建。
确认 MySQL 版本和索引是否真支持 DESC
MySQL 8.0.11 及更早版本会静默忽略 DESC,建出来的仍是升序索引;只有 8.0.12+ 的 InnoDB 才真正按降序物理存储。
- 执行
SELECT VERSION(),确保返回 ≥8.0.12 - 运行
SHOW CREATE TABLE t,输出中必须明确出现类似created_at DESC——如果只写created_at,说明没生效 - 查系统表更准:
SELECT COLLATION FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_NAME = 't' AND INDEX_NAME = 'idx',结果为D才代表降序已落地(A就是升序) -
PRIMARY KEY (id DESC)在 8.0.11 及以前会被强制转成 ASC,别信语法糖
ORDER BY a DESC, b ASC 必须配 INDEX (a DESC, b ASC)
方向不一致不是“部分生效”,而是整个排序逻辑无法下推,必然触发 Using filesort。MySQL 不会把 INDEX (a DESC, b DESC) 用于 ORDER BY a DESC, b ASC,也不会用 INDEX (a ASC, b DESC) 去匹配它。
-
INDEX (a DESC, b ASC)只加速ORDER BY a DESC, b ASC;对ORDER BY a DESC单独使用也无效(缺少第二列,无法保证排序连续性) -
ORDER BY a DESC, b ASC, c DESC→ 索引必须是(a DESC, b ASC, c DESC),错一个方向或少一个列,Extra就会出现Using filesort - 联合索引中任意列方向变化,都意味着一套新索引:
INDEX (c1 ASC)和INDEX (c1 DESC)是两套独立物理结构,空间翻倍 - MySQL 8.0 禁止对同一列重复指定方向,如
(a ASC, a DESC)会直接报语法错误
单列 DESC 索引 + 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 - 对应索引必须是
INDEX (status, updated_at DESC),让status构成最左前缀,后续才能复用updated_at DESC排序 -
WHERE status IN ()、status > 10或直接省略WHERE,都会中断排序能力的传递 - 哪怕只错一个方向,
EXPLAIN的Extra字段仍会出现Using filesort
验证降序索引是否真正在工作
不能只看 EXPLAIN 的 key 字段是否命中索引名,关键盯紧三处:Extra、type、rows。
-
Extra出现Using filesort→ 没走成索引排序,无论你建了多少个DESC索引 -
type是ref或range,且rows显著小于总行数(比如百万级表降到几千)→ 基本确认走了索引扫描层排序 - MySQL 8.0.20+ 可用
EXPLAIN FORMAT=TREE,直接看执行计划里有没有filesort节点 - 别用
SELECT *:含TEXT字段时,MySQL 更倾向全字段排序,容易触发Using disk sort



















