联合索引遵循最左前缀匹配原则,即查询必须从最左列连续使用才能生效;如索引(a,b,c),where a=1、a=1 and b=2、a=1 and b=2 and c=3可命中,而where b=2或c=3则失效;字段顺序应按区分度高、查询频率高优先排列。

联合索引(也叫复合索引、组合索引)的设计核心是最左前缀匹配原则:查询条件必须从索引的最左侧列开始连续使用,才能有效利用该索引。不是“包含任意字段就能用”,也不是“顺序无关”。设计不当,索引可能完全失效。
最左前缀原则怎么起作用?
假设有联合索引 (a, b, c),以下查询能命中索引:
-
WHERE a = 1→ 匹配前1列 -
WHERE a = 1 AND b = 2→ 匹配前2列 -
WHERE a = 1 AND b = 2 AND c = 3→ 全部匹配 -
WHERE a = 1 AND b > 2 AND c = 3→a和b可用(b是范围查询,c不再用于索引查找,但可作为过滤项)
以下查询无法使用该索引进行查找(可能走全表扫描或仅用部分):
-
WHERE b = 2→ 缺少a,跳过最左列,索引失效 -
WHERE c = 3→ 同样跳过a和b -
WHERE a > 1 AND c = 3→a可用,但c无法跳过b直接定位,不参与查找
组合索引字段顺序怎么排?
顺序不是随意的,需综合以下三点权衡:
-
区分度高优先:把筛选性更强(值更分散、重复更少)的字段放左边,例如
user_id比status更适合作首列 -
查询频率高优先:经常单独出现在
WHERE中的字段,尽量靠左;若某字段几乎总和另一字段一起出现,可考虑将其放在后者之前 -
等值查询优先于范围查询:等值条件(
=、IN)可延续索引使用,而范围条件(>、BETWEEN、LIKE 'abc%')之后的字段无法用于索引查找,应把范围列放在等值列之后
举例:查询常为 WHERE status = ? AND create_time > ? AND user_id = ?,且 user_id 区分度最高,则推荐索引为 (user_id, status, create_time) —— 先锁死用户,再按状态过滤,最后用时间范围收口。
哪些情况会意外导致联合索引失效?
即使写了符合最左前缀的条件,也可能因写法问题让优化器弃用索引:
- 对索引列使用函数或表达式:
WHERE YEAR(create_time) = 2024→create_time列无法走索引 - 隐式类型转换:
WHERE mobile = 13812345678(mobile 是 VARCHAR),MySQL 可能转成数字比较,导致索引失效 - 使用
!=或NOT IN(尤其在非空场景下)可能使优化器放弃索引 -
OR连接不同字段:WHERE a = 1 OR b = 2,除非a和b都有独立索引,否则联合索引(a,b)通常不生效 -
LIKE以通配符开头:WHERE name LIKE '%abc'→ 无法利用索引;LIKE 'abc%'可以
要不要为每个查询都建联合索引?
不必,也不建议。应遵循:
- 优先覆盖高频、高代价查询:先看慢查询日志,挑执行频次高、扫描行数多的 SQL 重点优化
-
复用优于堆叠:比如已有
(a, b, c),又出现WHERE a = ? AND b = ?,无需再建(a,b);但若新增WHERE b = ? AND c = ?,则需另建(b,c)或调整原索引顺序 - 注意索引维护成本:每多一个索引,INSERT/UPDATE/DELETE 就多一分开销,且占用更多磁盘和内存;单表联合索引建议控制在 3~5 个以内,字段总数不超过 5 个为宜
-
善用覆盖索引:如果查询只需返回索引列(如
SELECT a,b FROM t WHERE a=1 AND b=2),配合(a,b)索引即可避免回表,提升明显
不复杂但容易忽略。关键不是堆索引,而是让每个索引都真正被用上。










