联合索引能避免using filesort,是因为mysql的b+树索引天然有序,当order by字段顺序、方向与索引定义完全一致时,优化器可直接按叶子节点顺序扫描,跳过额外排序;此时explain的extra显示using index或为空,而非using filesort。

为什么联合索引能避免 Using filesort
MySQL 的 B+ 树索引天然有序,只要 ORDER BY 字段的顺序、方向和联合索引定义完全一致,优化器就能直接按索引叶子节点顺序扫描数据,跳过额外排序步骤。这时 EXPLAIN 的 Extra 列会显示 Using index 或空值,而不是 Using filesort。关键不是“有没有索引”,而是“索引能不能被排序逻辑连续命中”。
联合索引字段顺序必须严格匹配 ORDER BY
索引字段顺序必须是 ORDER BY 字段的**最左前缀连续子集**,且不能跳过中间列。
- 查询写成
ORDER BY a, b, c→ 索引必须是(a, b, c)或(a, b, c, d);(a, c)或(b, c)都无效 - 有
WHERE条件时,等值字段优先放前面:比如WHERE status = 'paid' ORDER BY created_at DESC→ 索引建为(status, created_at),不是反过来 - 如果
WHERE含范围条件(如user_id > 100),后续字段无法用于排序——此时created_at即使在索引里也大概率失效
ASC/DESC 方向不一致就可能触发 filesort
MySQL 8.0+ 支持显式声明降序索引,但前提是定义和查询**完全一致**;旧版本只支持全 ASC 或全 DESC。
- 索引建为
(a ASC, b DESC)→ 只有ORDER BY a ASC, b DESC能用上 -
ORDER BY a DESC, b DESC在 8.0+ 可走反向扫描,但若索引没声明方向(即(a, b)),则ORDER BY a DESC, b DESC可能仍被拒绝 - 隐式转换也会破坏方向一致性:比如
WHERE phone = 13800138000(数字)对比phone VARCHAR(20),会导致整个索引排序路径中断
覆盖索引不是可选项,而是稳定性的关键一环
即使排序走了索引,如果 SELECT * 或大量非索引字段导致回表代价高,优化器可能主动放弃索引排序,改走全表扫描 + filesort。
- 优先把
WHERE条件列、ORDER BY列、以及高频SELECT字段一起放进联合索引,例如:(user_id, created_at, id, name, email) - 别盲目塞全部字段:
TEXT、BLOB不允许建索引,大字段也会让索引体积膨胀、写入变慢 - 用
EXPLAIN FORMAT=TREE或EXPLAIN ANALYZE观察是否真用了索引排序,而不仅是“key列非 NULL”
最容易被忽略的是:索引存在 ≠ 排序生效。哪怕字段顺序、方向都对,一旦统计信息过期、隐式类型转换发生、或优化器预估行数严重偏差,它仍可能绕开你的索引。上线前务必在真实数据量下跑 EXPLAIN,而不是只看 DDL 是否执行成功。











