一、核心概念
最左前缀匹配是MySQL联合索引(复合索引)的一个重要规则:在使用联合索引时,查询条件必须从索引的最左列开始,并且不能跳过中间列。
例如,对于联合索引 INDEX(a, b, c):
- ✅ 可以使用:
WHERE a=1、WHERE a=1 AND b=2、WHERE a=1 AND b=2 AND c=3 - ❌ 无法使用:
WHERE b=2、WHERE c=3、WHERE b=2 AND c=3
二、原理详解
1. B+树存储结构
联合索引在B+树中的存储方式是先按第一列排序,第一列相同时按第二列排序,以此类推。
以 INDEX(a, b, c) 为例,数据在B+树中的排列:
(1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(1, 2, 2)
(2, 1, 1)
(2, 1, 2)
(2, 2, 1)
2. 为什么必须遵守最左前缀
本质原因:B+树的有序性只对最左列有效,后续列只在前面列相同的情况下才是有序的。
- 场景1:查询
WHERE a=1→ a列全局有序,可以快速定位 - 场景2:查询
WHERE b=2→ b列在全局范围内是无序的(如上例,b=1和b=2交替出现),无法使用二分查找 - 场景3:查询
WHERE a=1 AND c=3→ 可以利用a定位范围,但c在该范围内无序,需要回表检查
3. 最左前缀的范围
“最左前缀”不仅指完整的列,还包括:
- 字符串前缀:
INDEX(name)可以匹配WHERE name LIKE '张%' - 连续列组合:
INDEX(a,b,c)中的(a)、(a,b)、(a,b,c)都是有效前缀
三、典型场景与注意事项
1. 范围查询的影响
-- 索引 INDEX(a, b, c)
WHERE a=1 AND b>10 AND c=5
- a:精确匹配,使用索引
- b:范围查询,使用索引
- c:无法使用索引(范围查询后的列失效)
2. 函数与计算
-- 索引 INDEX(create_time)
WHERE DATE(create_time) = '2025-11-02' -- ❌ 索引失效
WHERE create_time >= '2025-11-02 00:00:00'
AND create_time < '2025-11-03 00:00:00' -- ✅ 索引有效
3. 优化器可能的优化
MySQL 8.0+ 引入了索引跳跃扫描(Index Skip Scan),在某些特定场景下可以跳过最左列,但这不是常规优化手段。
四、性能优化建议
1. 索引列顺序设计
- 区分度高的列放前面:筛选效果好,减少扫描行数
- 等值查询列放前面:避免范围查询阻断后续列
- 常用查询列放前面:提高索引利用率
2. 避免冗余索引
-- 已有 INDEX(a, b, c)
-- 则无需再创建 INDEX(a) 和 INDEX(a, b)
-- 因为最左前缀原则已覆盖
3. 合理使用索引覆盖
-- 索引 INDEX(a, b, c)
SELECT a, b, c FROM table WHERE a=1 AND b=2
-- 无需回表,直接从索引获取所有数据
五、面试总结
最左前缀匹配的本质是联合索引在B+树中的排序方式决定的:
- 联合索引按照从左到右的列顺序依次排序
- 只有最左列在全局范围内有序,后续列只在前面列相同时有序
- 因此查询必须从最左列开始,才能利用B+树的有序性进行快速定位
- 范围查询会导致后续列无法使用索引(因为范围内后续列无序)
- 索引设计时要考虑查询频率、区分度和列的顺序
遵守最左前缀原则是高效使用联合索引的基础,也是MySQL索引优化的核心知识点。