ORDER BY慢的根本原因是未跳过排序,而非排序本身;关键看EXPLAIN中Extra是否出现Using filesort:有则未走索引排序,无且key显示索引才真正优化到位。

ORDER BY没走索引,根本不是排序慢,而是没跳过排序
MySQL 里 ORDER BY 慢,90% 不是因为数据多或排序算法差,而是执行计划里出现了 Using filesort——这意味着 MySQL 必须把结果先捞出来,再额外做一次排序。真正快的路径是 Index Order:直接按索引 B+ 树的物理顺序读取,天然有序,零额外开销。
关键判断标准就一条:EXPLAIN 输出中 Extra 字段有没有 Using filesort。有,就是没走索引排序;没有,且 key 显示用了某个索引,才算真正优化到位。
为什么联合索引 (a,b,c) 无法加速 ORDER BY b, c?
这不是 MySQL 的 bug,而是索引结构决定的:B+ 树只保证“从左到右连续前缀”有序。索引 (a,b,c) 的数据在磁盘上是先按 a 排序,a 相等时再按 b 排,b 也相等时才按 c 排。所以 ORDER BY b, c 在全局范围内并不有序——除非你加了 WHERE a = ?,让优化器知道只查某一个 a 值下的数据,这时 b,c 才局部有序。
-
WHERE a = 1 ORDER BY b, c→ 可用(a,b,c)索引消除排序 -
WHERE a > 1 ORDER BY b, c→Using filesort,因为a范围查询后,b,c不再连续有序 -
ORDER BY b, c(无 WHERE)→ 即使有(a,b,c)索引,也触发Using filesort
ORDER BY UPPER(name) 或 ORDER BY created_at + INTERVAL 1 DAY 为什么失效?
函数或表达式会“包裹”字段,导致索引值无法直接比对。MySQL 无法把 UPPER(name) 的结果映射回索引里的原始 name 值,更没法利用其顺序性。同理,created_at + INTERVAL 1 DAY 是计算后的值,索引里存的是原始时间戳。
-
ORDER BY name→ 可走INDEX(name) -
ORDER BY UPPER(name)→ 必然Using filesort -
WHERE name = 'alice' ORDER BY name→ 单行结果,无所谓排序,但写法本身不破坏索引 - 真要按大写排序,建生成列索引:
ALTER TABLE t ADD COLUMN name_upper VARCHAR(100) STORED AS (UPPER(name)), ADD INDEX idx_name_upper (name_upper)
MySQL 8.0+ 支持 DESC 索引,但混合 ASC/DESC 还是容易踩坑
MySQL 8.0 开始允许在建索引时显式声明方向,比如 INDEX (a ASC, b DESC)。但这不等于“自动适配任意排序方向”,而是严格匹配:只有 ORDER BY a ASC, b DESC 才能命中;换成 ORDER BY a DESC, b ASC 或 ORDER BY a ASC, b ASC 都会失效。
- 老版本(5.7 及以前)压根不认索引里的
DESC声明,建了也当ASC用 - 没显式声明方向的索引(如
INDEX(a,b)),默认全是ASC,ORDER BY a DESC, b DESC在 8.0+ 可用,但ORDER BY a ASC, b DESC仍不行 -
EXPLAIN中key显示用了索引,但Extra还有Using filesort?八成是方向没对齐
ORDER BY 走了索引,如果 SELECT * 导致回表代价过高,优化器也可能主动放弃索引排序,退回到 filesort。这时候得靠覆盖索引——把所有 SELECT 字段都塞进联合索引里,避免回表。


















