能,但仅当order by方向与降序索引定义完全一致(含顺序和升降序)、where条件满足最左前缀且操作符不破坏顺序性时,才能跳过filesort。

MySQL 8.0 降序索引真能跳过 ORDER BY 排序?
能,但只在特定条件下成立。MySQL 8.0 支持真正意义上的降序索引(INDEX (col DESC)),不是以前的“逻辑降序、物理升序”假降序。这意味着如果查询是 ORDER BY col DESC,且该列上有 INDEX (col DESC),优化器大概率会直接按索引顺序读取,避免 filesort。
常见错误现象:EXPLAIN 显示 Extra: Using filesort,即使有索引;或者明明建了 INDEX (a DESC, b ASC),但 ORDER BY a DESC, b DESC 仍触发排序——因为方向不匹配。
- 降序索引只对严格匹配的
ORDER BY方向生效:索引是(a DESC, b ASC),就只加速ORDER BY a DESC, b ASC,不加速ORDER BY a DESC, b DESC - 联合索引中,ASC/DESC 必须和
ORDER BY子句完全一致(包括顺序和方向),否则无法跳过排序 - WHERE 条件中的列必须是索引最左前缀,且比较操作符不能破坏顺序性(比如
WHERE a > 10可以,WHERE a != 10就不行)
怎么建一个真正有用的降序索引?
别直接套用旧习惯。MySQL 5.7 及以前建 INDEX (col DESC) 实际上等价于 INDEX (col),8.0 才真正支持物理降序存储。
使用场景:分页查询末尾数据(如“最新 20 条”)、时间倒序展示、排行榜从高到低。
- 建索引时明确写
DESC:CREATE INDEX idx_created_desc ON orders (created_at DESC); - 联合索引注意方向组合:
CREATE INDEX idx_status_created ON orders (status ASC, created_at DESC);—— 这适合WHERE status = 'shipped' ORDER BY created_at DESC - 避免混用方向却无对应查询:比如建了
(a ASC, b DESC),但业务里只查ORDER BY a DESC, b ASC,这个索引基本闲置
EXPLAIN 看不到 Using filesort 就一定走索引排序?
不一定。得看 type 和 key 字段是否合理,以及是否真的用了索引的排序能力。
性能影响很实际:filesort 是内存或磁盘排序,IO 和 CPU 开销明显;而索引扫描是顺序 I/O,快得多,尤其数据量大时。
- 确认
key列显示你建的降序索引名,而不是其他索引 -
type最好是range或ref,而不是ALL(全表扫描) - 如果
Extra是Using index+ 没有Using filesort,说明既用了覆盖索引,又免了排序——这是最优情况 - 注意
SELECT *容易让覆盖索引失效,导致回表,此时即使免了排序,整体性能也不一定好
哪些地方容易被忽略?
最常踩的坑不在语法,而在语义理解偏差。
- 降序索引不能加速
MIN()/MAX()查询:比如SELECT MIN(created_at) FROM t,哪怕有INDEX(created_at DESC),MySQL 仍要遍历到索引末尾,不如INDEX(created_at ASC)直接取第一条 - NULL 值排序行为:MySQL 中
NULL默认排在非空值前面(无论 ASC/DESC),但索引里NULL的物理位置取决于存储引擎实现,可能影响范围扫描边界 - 分区表、JSON 列、函数索引目前不支持降序修饰符,
INDEX ((json_col->'$.id') DESC)会报错
降序索引不是银弹,它只在“查询排序方向与索引定义方向严丝合缝”时才真正省事。多一个方向不匹配,就退回 filesort。建之前,先看清楚 EXPLAIN 里的 ORDER BY 和 key 是怎么对上的。











