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—— 这个细节,线上慢查里藏得最多。
