🔗 联合索引 & 最左前缀 & 索引失效
联合索引为什么必须从左开始匹配?范围查询怎么中断?8 种让索引失效的坑一次排掉。
什么是联合索引
🔗 多列索引
联合索引(Composite Index)是在多个列上建立的索引。
MySQL 按索引定义时列的顺序,把这些列的值拼接后构建 B+ 树。
例如联合索引 (a, b, c) 相当于创建了三个索引:(a)、(a,b)、(a,b,c)。
🎯 核心:最左前缀原则
查询条件必须从索引的最左列开始匹配,才能有效使用索引。
MySQL 一直向右匹配,直到遇到范围查询(> < BETWEEN LIKE)就停止。
最左前缀匹配规则
| SQL 条件 | 能否走索引 | 说明 |
|---|---|---|
| WHERE a = 1 | ✓ 使用 | 第一列 |
| WHERE a=1 AND b=2 | ✓ 使用 | 第一、二列 |
| WHERE a=1 AND b=2 AND c=3 | ✓ 全部 | 用全索引 |
| WHERE a=1 AND c=3 | △ 部分 | a 走索引,c 不走(跳过 b) |
| WHERE b = 2 | ✗ 不使用 | 跳过第一列 |
| WHERE b=2 AND c=3 | ✗ 不使用 | 跳过第一列 |
范围查询中断规则
⛔ 范围查询会中断
遇到 > < BETWEEN LIKE 这类范围查询,MySQL 就停止向右匹配,范围条件之后的列无法走索引。
所以尽量把范围条件放到联合索引的最后。
✅ IN 不中断
IN 和 = 不影响后续列——MySQL 会把 IN 优化成多个等值条件,所以 IN 后面的列还能走索引。
| SQL 条件 | 走索引情况 |
|---|---|
| WHERE a > 1 AND b = 2 | a 走范围,b 不参与(a 范围后中断) |
| WHERE a=1 AND b > 2 AND c=3 | a、b 走(等值→范围),c 不走 |
| WHERE a=1 AND b IN (2,3) AND c=4 | 全部走(IN 优化为等值) |
8 种让索引失效的坑
隐式类型转换
WHERE phone = 13500001111(字段是 varchar,传数字)→ 类型转换导致索引失效。要传字符串。
最左前缀不满足
联合索引 (a,b),却 WHERE b=... 跳过了 a → 失效。条件要从最左列开始。
LIKE 以 % 开头
WHERE name LIKE '%new' → 前导通配符无法利用索引;改成 'new%' 才能走。
OR 条件未全索引
WHERE id=1 OR name='x' → 若 name 没索引,OR 的其它列无法索引,整条失效。
索引列参与计算
WHERE salary > 1.1 * 1000 → 对索引列做运算会使索引失效;应把计算移到右侧或写死。
IS NOT NULL
WHERE id IS NOT NULL → 可能使索引失效(NOT NULL 无法用索引做等值定位)。
NOT IN / <> 操作
WHERE id NOT IN (1,2) 或 id <> 3 → 不等/取反操作通常无法走索引。
优化器选择
有时即使能用索引,优化器按成本模型判断全表扫描更划算(如查询量占比大)→ 主动不用。
设计要点
区分度高的列放前面
联合索引列顺序至关重要,通常把区分度高的列放最前。
范围条件放最后
范围查询会中断后续列,尽量把 > < BETWEEN 放联合索引末尾。
一个索引覆盖多个场景
(a, b) 可覆盖 a 和 (a,b) 两种查询,合理设计能减少索引数量。
IN 和 = 是朋友
IN 被优化成等值,不影响后续列走索引,和范围查询行为不同。
联合索引按列顺序拼接构建 B+ 树,遵循最左前缀原则——查询必须从最左列开始连续匹配,(a,b,c) 相当于 (a)、(a,b)、(a,b,c) 三个索引。范围查询(> < BETWEEN)会中断后续列,但 IN 会优化成等值不影响。8 大失效坑:隐式类型转换、最左前缀不满足、LIKE %开头、OR 未全索引、索引列运算、IS NOT NULL、NOT IN/<>,、优化器选择。设计上区分度高的列放前、范围条件放后。
联合索引就是在多个列上建的索引,MySQL 按定义时列的顺序把这些列的值拼接后构建 B+ 树。最左前缀原则是说查询条件必须从索引的最左列开始连续匹配才能用索引,比如 (a,b,c) 相当于建了 (a)、(a,b)、(a,b,c) 三个索引,所以 WHERE a=1 能用,WHERE b=2 跳过第一列就不能用。而且遇到范围查询就停止向右匹配。
a=1 能走,用第一列;b=2 不能走,跳过了最左列 a;a=1 AND c=3 是 a 走索引,但 c 跳过了 b 所以 c 不走;a=1 AND b>2 AND c=3 是 a 走等值、b 走范围,但遇到范围查询就中断,所以 c 不走。关键是最左前缀要连续,范围查询会中断后面的列。
我总结几个高频的:隐式类型转换,比如 varchar 字段传数字;最左前缀不满足,联合索引跳过了最左列;LIKE 以 % 开头,前导通配符用不了索引;OR 条件里有没索引的列;对索引列做计算或函数;IS NOT NULL;NOT IN 或 <> 这类取反操作;还有可能是优化器判断全表扫描更划算主动不用索引。