联合索引能直接支撑多字段排序,前提是索引列顺序、方向和order by子句严格匹配;否则mysql会退回到using filesort,性能断崖式下降。

联合索引能直接支撑多字段排序,前提是索引列顺序、方向和 ORDER BY 子句严格匹配;否则 MySQL 会退回到 Using filesort,性能断崖式下降。
联合索引必须与 ORDER BY 字段顺序完全一致
MySQL 只有在索引的最左前缀能覆盖 ORDER BY 所有列时,才可能跳过文件排序。比如查询是 ORDER BY a ASC, b DESC, c ASC,那么有效索引只能是 INDEX(a, b, c) 或更长的前缀(如 INDEX(a, b, c, d)),但不能是 INDEX(b, a, c) 或 INDEX(a, c, b)。
- 即使
WHERE条件只用到a = ?,只要ORDER BY是a, b, c,索引(a, b, c)就能同时服务过滤和排序 - 如果
ORDER BY b, a,哪怕表上有(a, b)索引,也完全无法利用——顺序错位即失效 -
WHERE a = 1 ORDER BY b, c这种“跳过最左列”的排序,(a, b, c)索引对排序部分无效,仍会触发Using filesort
MySQL 8.0+ 要显式声明 DESC 才能匹配降序排序
在 MySQL 8.0 之前,索引内部总是按升序存储,ORDER BY a DESC, b ASC 即使有 INDEX(a, b),也只能用上 a 的索引扫描,b 部分仍要文件排序。8.0+ 支持真正的降序索引,必须显式写出方向:
- 正确写法:
CREATE INDEX idx_a_desc_b_asc ON t (a DESC, b ASC) - 错误写法:
CREATE INDEX idx_a_b ON t (a, b)—— 它无法加速ORDER BY a DESC, b ASC - 执行
EXPLAIN后,若Extra字段不再出现Using filesort,说明排序已走索引
避免回表才能真正发挥联合索引排序价值
光让排序走索引还不够,如果 SELECT * 或返回非索引字段,MySQL 仍需根据主键回表取数据,I/O 开销大。覆盖索引是关键:
- 例如查询
SELECT id, name, created_at FROM orders WHERE user_id = 123 ORDER BY created_at DESC,理想索引是INDEX(user_id, created_at, id, name)(注意:id和name必须包含在索引中) - 字段顺序必须满足最左前缀:过滤列
user_id在最左,排序列created_at紧随其后,查询返回字段补在后面 - 如果
name是TEXT类型,不建议加入索引——索引长度超限或效率反降,此时应权衡是否接受回表
范围查询后无法继续利用排序索引
这是最容易忽略的坑:一旦 WHERE 中某个索引列用了范围条件(>、、<code>BETWEEN、LIKE 'xxx%'),该列之后的所有索引字段,对排序就失效了。
- 索引
(a, b, c),查询WHERE a = 1 AND b > 10 ORDER BY c→c仍可走索引排序 - 但查询
WHERE a > 1 ORDER BY b, c→b和c全部失效,必然Using filesort - 此时没有银弹:要么改写为等值 + 范围组合(如加一个高区分度的等值前置条件),要么接受排序开销,或考虑分区裁剪
最麻烦的情况是业务要求动态排序字段(比如前端可选按价格/销量/时间任意组合),这时单个联合索引无法覆盖所有排列,需要结合查询路由、物化视图或应用层归并,而不是硬塞一堆索引。











