MySQL联合索引与最左前缀原则
MySQL联合索引与最左前缀原则
联合索引
联合索引:在MySQL(更准确说是InnoDB引擎)中,联合索引就是对多个列一起建立一个B+Tree索引,例如:
1 | CREATE INDEX idx_abc ON user(a, b, c); |
这不是建了三个索引,而是建了一棵按照(a,b,c)排序的B+Tree。
理解关键点:
这棵树里的“键”是一个有序的三元组:
(a1, b1, c1)
(a1, b1, c2)
(a1, b2, c1)
(a2, b1, c1)
它的排序规则是:
先按 a 排序 → a 相同按 b 排序 → b 相同按 c 排序
这就像字典排序,先看姓,再看名,再看中间名。
最左前缀原则
最左前缀原则:查询条件必须从索引的最左列开始,且不能跳过中间列。
还是上面这个索引 (a, b, c)。
可以命中索引的情况:
1)where a = 1
2)where a = 1 and b = 2
3)where a = 1 and b = 2 and c = 3
4)where a = 1 and c = 3 (可以用到 a,但 c 用不上)
不能有效使用索引的情况:
1)where b = 2
2)where c = 3
3)where b = 2 and c = 3
为什么?
因为 B+Tree 是按照 a → b → c 的顺序排好的。
如果你不指定 a,相当于你要在一本“按姓氏排序的电话簿”里找所有叫“张三”的人,但你不知道姓是什么。那就只能全书翻。
为什么“不能跳过列”?
例如:
1 | where a = 1 and c = 3 |
这里 a 是最左列,所以可以用索引定位到 a=1 这段范围。
但由于 b 没有参与过滤,MySQL 无法直接利用 c 来进一步缩小范围,只能在 a=1 的区间里扫描,然后再过滤 c=3。
这就是所谓的:“遇到范围查询或跳列就停止匹配。”
范围查询截断索引
范围查询会截断索引。
例如:
1 | where a = 1 and b > 2 and c = 3 |
这里 b 是范围查询(> 2),
一旦遇到范围条件,索引匹配就停止在 b。
也就是说:
a ✔
b ✔
c ❌
因为 B+Tree 在 b>2 之后已经是一个范围区间,无法再保证 c 的有序性用于快速定位。
覆盖索引
覆盖索引:如果查询的列都包含在联合索引的列中,并且查询条件满足最左前缀原则,那么MySQL可以直接从索引叶子节点获取数据,而不需要回表查询。
如果你的查询:
1 | select a, b, c from user where a = 1 and b = 2; |
由于索引本身就包含 (a,b,c),
MySQL 可以直接从索引叶子节点取数据,不回表。
这叫“覆盖索引”,性能会更高。
