联合索引字段顺序为什么不能随便调换
联合索引的字段顺序直接影响查询能否命中索引,本质是 B+ 树的排序规则决定的。MySQL 会按定义顺序逐列构建索引项,
(a, b, c)的索引树先按
a排序,
a相同时再按
b排序,
a,b都相同时才按
c排序。
这意味着只有满足「最左前缀匹配」的条件才能走索引:
WHERE a = 1✅ 走索引
WHERE a = 1 AND b = 2✅ 走索引
WHERE a = 1 AND b = 2 AND c = 3✅ 走索引
WHERE b = 2❌ 不走索引(跳过
a)
WHERE a = 1 AND c = 3⚠️ 只用到
a,
c无法利用(
b缺失导致
c无序)
如何创建高效联合索引:三个实操原则
建索引不是堆字段,而是围绕高频查询模式设计。常见误区是把所有 WHERE 字段全塞进去,结果索引大、更新慢、还用不上。
把等值查询字段放最左:例如WHERE status = 'done' AND user_id = 123 AND created_at > '2024-01-01',应建
(status, user_id, created_at);
status和
user_id是等值,
created_at是范围,放最后 高区分度字段优先但不绝对:比如
gender(只有 'M'/'F')区分度极低,即使放最左也难提升效率;但如果查询总是
WHERE gender = 'F' AND city = 'Beijing',且
city值太多,反而先筛
gender能快速缩小扫描范围 避免冗余索引:已有
(a, b),再建
(a)就是冗余;但
(a, b)和
(a, b, c)不冗余——后者支持三字段查询,前者不支持
验证联合索引是否生效:看 EXPLAIN
的关键字段
别只看
type是否为
ref或
range,重点盯这三个输出:
key:显示实际使用的索引名,为空说明没走索引
key_len:表示用了索引的多少字节。例如
key_len = 10对应
(a, b)中
a占 4 字节 +
b占 6 字节,说明两列都用上了;若
key_len = 4,大概率只用了
a
Extra中出现
Using index表示覆盖索引(无需回表),出现
Using where; Using index是理想状态;若出现
Using filesort或
Using temporary,说明排序或分组没走索引,可能需要调整索引或 SQL
EXPLAIN SELECT * FROM orders WHERE status = 'shipped' AND user_id = 5566;
什么时候联合索引会“失效”:几个典型陷阱
即使语法正确、字段顺序合理,以下操作也会让联合索引退化为全表扫描或部分失效:
对索引字段做函数操作:WHERE YEAR(created_at) = 2024→ 改成
WHERE created_at >= '2024-01-01' AND created_at隐式类型转换:
user_id是
INT,但写成
WHERE user_id = '123'(字符串),可能导致索引失效(取决于 MySQL 版本和字符集) 使用
OR连接非同一索引字段:
WHERE a = 1 OR b = 2,除非
a和
b分别有单列索引,否则联合索引
(a,b)无法整体利用 LIKE 左模糊:
WHERE name LIKE '%abc'无法用索引;
WHERE name LIKE 'abc%'可以(前提是
name在联合索引最左或连续前缀位置)
联合索引不是银弹,它的价值高度依赖查询写法和数据分布。上线前务必用真实数据量 +
EXPLAIN验证,而不是只看测试库里几条记录的执行速度。
