最左前缀法则 (Leftmost Prefix Rule) 是 MySQL 联合索引最核心的使用原则。如果不理解它,建立的索引很可能就是无效的。
简单来说:联合索引就像查字典,必须按照顺序从最左边开始查,不能跳过,也不能乱序。
💡 记忆口诀:
“带头大哥不能死,中间兄弟不能断。”
如果“带头大哥”没在 WHERE 条件里,整个索引直接失效。 如果“中间兄弟”断了,后面的字段就接不上了,索引匹配就此终止。
假设建立联合索引 idx_a_b_c (a, b, 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
a=1):✅ 很快,班级有序。a=1 and b=170):✅ 很快,班级确定后,身高是有序的。b=170):❌ 无法找。因为全校各个班都有 170cm 的人,他们在队伍里是散乱的。(带头大哥死了)a=1 and c=10):⚠️ 部分失效。先找到1班,但在1班内部,身高不同的人学号是乱的,所以只能用到 a,c 用不到索引。(中间兄弟断了)假设表结构中有联合索引:KEY idx_abc (a, b, c)
| SQL 查询条件 | 索引使用情况 | 状态 | 解释 |
|---|---|---|---|
WHERE a=1 | a | ✅ | 最左匹配成功。 |
WHERE a=1 AND b=2 | a, b | ✅ | 连续匹配成功。 |
WHERE a=1 AND b=2 AND c=3 | a, b, c | ✅ | 完美匹配所有字段。 |
WHERE b=2 AND c=3 | NULL | ❌ | 带头大哥 a 没出现,全表扫描。 |
WHERE a=1 AND c=3 | a | ⚠️ | 中间兄弟 b 断了。a 走索引,c 只能作为过滤条件(可能触发 ICP)。 |
WHERE a=1 AND b>2 AND c=3 | a, b | ⚠️ | 范围查询阻断后续。b 是范围查询,导致后面的 c 无序,无法走索引。 |
问:如果写成
WHERE b=2 AND a=1,顺序反了,是不是就不符合最左前缀了?
答:完全符合,放心用。
MySQL 的 优化器 (Optimizer) 非常聪明,它在执行前会自动调整 WHERE 条件的顺序,将其优化为 a=1 AND b=2 以适配索引。
重点是“有没有”这个字段,而不是 SQL 语句里书写的“顺序”。
为什么会有这个法则?这由 B+ 树的物理存储结构决定。
在联合索引 (a, b, c) 的 B+ 树数据结构中:
a 是绝对有序的 (1, 1, 2, 2, 3...)。b 只有在 a 相同的时候才是有序的。全局看 b 是乱序的 (2, 5, 1, 4...)。c 只有在 a 和 b 都确定的情况下才是有序的。结论:如果你跳过 a 直接找 b,B+ 树就“懵”了,因为它不知道往左走还是往右走,只能退化为全表扫描。
>, <, BETWEEN),请把它放在联合索引的最后,因为它会阻断后续字段使用索引。