MySQL的ORDER BY不一定用索引,仅当排序字段是同一联合索引的最左前缀连续部分且未被WHERE截断时才避免filesort;EXPLAIN中无Using filesort且key显示索引即表示走索引排序。

No,MySQL 的 ORDER BY 不一定会用索引 —— 它只在满足特定结构约束时才跳过 filesort,直接利用索引顺序返回结果。
什么时候 ORDER BY 能走索引?
核心就一条:排序字段必须是**同一个联合索引的最左前缀连续部分**,且该索引未被 WHERE 条件“截断”。
- 表有索引
INDEX idx_name_age_pos (name, age, position) -
SELECT * FROM users WHERE name = 'Alice' ORDER BY age✅ 走索引(name用于过滤,age是紧接其后的排序字段) -
SELECT * FROM users WHERE age = 25 ORDER BY name❌ 不走索引(age不是最左字段,无法定位 B+ 树起点) -
SELECT * FROM users WHERE name = 'Alice' ORDER BY position❌ 大概率Using filesort(跳过了age,破坏最左连续性)
EXPLAIN 中怎么一眼识别是否用了索引排序?
看 Extra 列:
- 出现
Using filesort→ MySQL 额外做了排序,没用上索引顺序 - 没有
Using filesort,且key显示用了某个索引 → 排序由索引天然有序性完成 - 额外提示:
Using index表示覆盖索引(不用回表),但和排序无关;它可能和排序共存,也可能不共存
EXPLAIN SELECT name, age FROM users WHERE name LIKE 'A%' ORDER BY age;
如果 key 是 idx_name_age_pos,Extra 是空(或只有 Using index),说明排序已由索引保障。
为什么加了单列索引,ORDER BY 还是 filesort?
常见误解:给 ORDER BY 字段单独建索引就万事大吉。错 —— 单列索引只对「纯排序无条件」或「仅按该字段 WHERE」有效。
-
SELECT * FROM orders ORDER BY created_at DESC;→ 单列索引INDEX(created_at)✅ 可用 -
SELECT * FROM orders WHERE user_id = 123 ORDER BY created_at DESC;→ 单列created_at索引 ❌ 几乎一定filesort(user_id没索引,先全表扫描再排序) - 正确做法:建联合索引
INDEX(user_id, created_at),让过滤 + 排序共用一棵 B+ 树
升序/降序混合、多字段排序的坑
InnoDB 的 B+ 树索引默认按升序存储;若 ORDER BY a ASC, b DESC,而索引是 (a, b),则 b DESC 无法利用索引顺序(MySQL 8.0+ 支持降序索引定义,但老版本不行)。
- MySQL 5.7 及更早:所有字段必须同向(都
ASC或都DESC)才可能走索引 - MySQL 8.0+:可建
INDEX(a ASC, b DESC),但需显式声明,且优化器不一定选它 - 避免写
ORDER BY id DESC LIMIT 20却只在id上建了升序索引 —— 仍可能触发filesort(尤其当id不是主键或聚簇顺序不匹配时)
真正决定是否用索引的,从来不是“有没有索引”,而是“查询条件 + 排序字段”能否对齐同一棵 B+ 树的遍历路径。哪怕索引存在,只要中间缺一环(比如 WHERE 断在中间、方向不一致、字段不在同一索引里),MySQL 就只能老老实实开 sort_buffer 做 filesort —— 这个细节,线上慢查里藏得最多。









