编辑
2025-12-12
Mysql
00

目录

MySQL 联合索引:最左前缀法则详解
1\. 核心口诀
2\. 形象比喻:排队机制
3\. 实战案例演示
4\. 常见误区 (FAQ)
5\. 底层原理 (B+ 树)
6\. 优化建议

MySQL 联合索引:最左前缀法则详解

最左前缀法则 (Leftmost Prefix Rule) 是 MySQL 联合索引最核心的使用原则。如果不理解它,建立的索引很可能就是无效的。

简单来说:联合索引就像查字典,必须按照顺序从最左边开始查,不能跳过,也不能乱序。

1. 核心口诀

💡 记忆口诀:

“带头大哥不能死,中间兄弟不能断。”

  • 带头大哥:索引定义的第一个字段。
  • 中间兄弟:索引中间的字段。

如果“带头大哥”没在 WHERE 条件里,整个索引直接失效。 如果“中间兄弟”断了,后面的字段就接不上了,索引匹配就此终止。

2. 形象比喻:排队机制

假设建立联合索引 idx_a_b_c (a, b, c),就好比学校排队,规则如下:

  1. 先按 班级 (a) 从小到大排。
  2. 如果班级一样,再按 身高 (b) 从小到大排。
  3. 如果身高也一样,再按 学号 (c) 从小到大排。
graph TD
    A[班级 a <br> 全局有序] -->|a 相同| B(身高 b <br> 局部有序)
    B -->|a,b 都相同| C(学号 c <br> 局部有序)
    
    style A fill:#e1f5fe,stroke:#01579b
    style B fill:#fff9c4,stroke:#fbc02d
    style C fill:#e8f5e9,stroke:#2e7d32
  • 找“1班”的人 (a=1):✅ 很快,班级有序。
  • 找“1班”里“170cm”的人 (a=1 and b=170):✅ 很快,班级确定后,身高是有序的。
  • 找“170cm”的人 (b=170):❌ 无法找。因为全校各个班都有 170cm 的人,他们在队伍里是散乱的。(带头大哥死了)
  • 找“1班”里“学号10”的人 (a=1 and c=10):⚠️ 部分失效。先找到1班,但在1班内部,身高不同的人学号是乱的,所以只能用到 ac 用不到索引。(中间兄弟断了)

3. 实战案例演示

假设表结构中有联合索引:KEY idx_abc (a, b, c)

SQL 查询条件索引使用情况状态解释
WHERE a=1a最左匹配成功。
WHERE a=1 AND b=2a, b连续匹配成功。
WHERE a=1 AND b=2 AND c=3a, b, c完美匹配所有字段。
WHERE b=2 AND c=3NULL带头大哥 a 没出现,全表扫描。
WHERE a=1 AND c=3a⚠️中间兄弟 b 断了a 走索引,c 只能作为过滤条件(可能触发 ICP)。
WHERE a=1 AND b>2 AND c=3a, b⚠️范围查询阻断后续b 是范围查询,导致后面的 c 无序,无法走索引。

4. 常见误区 (FAQ)

问:如果写成 WHERE b=2 AND a=1,顺序反了,是不是就不符合最左前缀了?

答:完全符合,放心用。

MySQL 的 优化器 (Optimizer) 非常聪明,它在执行前会自动调整 WHERE 条件的顺序,将其优化为 a=1 AND b=2 以适配索引。

重点是“有没有”这个字段,而不是 SQL 语句里书写的“顺序”。

5. 底层原理 (B+ 树)

为什么会有这个法则?这由 B+ 树的物理存储结构决定。

在联合索引 (a, b, c) 的 B+ 树数据结构中:

  1. 全局看a 是绝对有序的 (1, 1, 2, 2, 3...)
  2. 局部看b 只有在 a 相同的时候才是有序的。全局看 b 是乱序的 (2, 5, 1, 4...)
  3. 同理,c 只有在 ab 都确定的情况下才是有序的。

结论:如果你跳过 a 直接找 b,B+ 树就“懵”了,因为它不知道往左走还是往右走,只能退化为全表扫描。

6. 优化建议

  1. 高频在前:将最常用的查询字段放在联合索引的最左边。
  2. 范围在后:如果某个字段经常用于范围查询(>, <, BETWEEN),请把它放在联合索引的最后,因为它会阻断后续字段使用索引。