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 = 'Ali
ce' 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+ 支持降序索引定义,但老版本不行)。
ASC 或都 DESC)才可能走索引INDEX(a ASC, b DESC),但需显式声明,且优化器不一定选它ORDER BY id DESC LIMIT 20 却只在 id 上建了升序索引 —— 仍可能触发 filesort(尤其当 id 不是主键或聚簇顺序不匹配时)真正决定是否用索引的,从来不是“有没有索引”,而是“查询条件 + 排序字段”能否对齐同一棵 B+ 树的遍历路径。哪怕索引存在,只要中间缺一环(比如 WHERE 断在中间、方向不一致、字段不在同一索引里),MySQL 就只能老老实实开 sort_buffer 做 filesort —— 这个细节,线上慢查里藏得最多。