首页/数据/数据库速查/联合索引列顺序(最左前缀与排序法则)
性能与调优57 条

联合索引列顺序(最左前缀与排序法则)

联合索引列序记忆法则:等值条件放前、范围条件放后、排序/分组列顺延;跳过最左列(如只用 b 查 (a,b))整个索引用不上。

数据库速查数据更新于 2026-10-13

联合索引列顺序是什么

联合索引能不能被用上,几乎完全取决于列的顺序。经验法则:等值条件的列放前面,范围条件的列放最后,排序与分组用到的列顺延其后。跳过最左列(用 (a,b) 索引却只按 b 查)整条索引用不上;而范围条件之后的列只能参与过滤,无法再用于定位。

基本信息

适用版本MySQL 5.7 / 8.0;跳跃扫描需 8.0.13+
最左前缀从索引第一列开始连续匹配才有效
范围截断范围列之后的列失去定位能力,只能过滤
排序顺延WHERE 等值列加 ORDER BY 后续列可避免额外排序
覆盖索引查询所需列全部在索引中时无需回表

典型使用场景

  • 多条件查询:区分度高的等值列放最前,筛掉最多数据
  • 分页排序:把排序列接在等值列之后,实现索引内有序输出
  • 区间统计:范围条件列放最后,前面留足等值列
  • 统计报表:构造覆盖索引,避免大量回表随机读
  • 高频后台查询:按真实 SQL 模式定列序,而不是按表的字段顺序
  • 唯一约束:把业务唯一键组合成联合唯一索引,顺带服务查询

三种查询对照

三种查询对照
-- 索引 idx(user_id, status, created_at)
SELECT * FROM orders WHERE user_id=1 AND status=2;               -- 用上 user_id+status
SELECT * FROM orders WHERE user_id=1 AND created_at>'2026-01-01'; -- user_id 定位,created_at 仍可范围内定位
SELECT * FROM orders WHERE status=2;                             -- 用不上,缺少最左列
SELECT id FROM orders WHERE user_id=1 AND status=2 ORDER BY created_at LIMIT 20;  -- 免排序
EXPLAIN SELECT * FROM orders WHERE user_id=1 AND status=2;       -- 看 key / key_len / Extra

EXPLAIN 关键列读法

列含义异常表现
key实际使用的索引为 NULL 说明没走上索引
key_len用到的索引字节长度明显偏小说明只有部分列生效
rows预估扫描行数数量级过大说明区分度不够
filtered过滤后剩余百分比很低说明大量行被逐行过滤
ExtraUsing index 为覆盖,Using filesort 为额外排序出现 filesort 或 temporary 需优化列序
「跳过中间列」后能否继续用后续列,取决于跳过的列是等值还是范围:等值可跳(8.0 索引跳跃扫描有限支持),范围不行。
列顺序一旦上线,调整等于重建索引;大表上代价不小。设计前用真实查询与列基数估算确认顺序,并保留 EXPLAIN 结果作为依据。

易错点

  • 把低区分度列(如状态、性别)放在最前,索引扫描行数依然巨大
  • 用 (a,b) 索引却只按 b 查询,索引完全用不上却以为已优化
  • 范围条件列放在中间,其后的列失去定位能力,只能逐行过滤
  • 只加索引不看列序与查询模式,索引数量涨了但执行计划依旧全表扫描
  • 在联合索引上频繁增删列,大表每次都触发重建,影响写入与复制延迟

数据来源与参考

  • MySQL 8.0 Reference Manual: Multiple-Column Indexes

相关工具

​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌