联合索引列顺序是什么
联合索引能不能被用上,几乎完全取决于列的顺序。经验法则:等值条件的列放前面,范围条件的列放最后,排序与分组用到的列顺延其后。跳过最左列(用 (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 / ExtraEXPLAIN 关键列读法
| 列 | 含义 | 异常表现 |
|---|---|---|
| key | 实际使用的索引 | 为 NULL 说明没走上索引 |
| key_len | 用到的索引字节长度 | 明显偏小说明只有部分列生效 |
| rows | 预估扫描行数 | 数量级过大说明区分度不够 |
| filtered | 过滤后剩余百分比 | 很低说明大量行被逐行过滤 |
| Extra | Using index 为覆盖,Using filesort 为额外排序 | 出现 filesort 或 temporary 需优化列序 |
「跳过中间列」后能否继续用后续列,取决于跳过的列是等值还是范围:等值可跳(8.0 索引跳跃扫描有限支持),范围不行。
列顺序一旦上线,调整等于重建索引;大表上代价不小。设计前用真实查询与列基数估算确认顺序,并保留 EXPLAIN 结果作为依据。