MySQL 索引的最左前缀匹配原则
最左前缀匹配原则(Leftmost Prefix Matching) 是指:
当 查询使用了复合索引(联合索引) 时,MySQL 会优先匹配索引的 最左列 ,然后逐步向右匹配,直到遇到无法匹配的列,此时索引匹配停止,不会继续使用后续的列索引。
1. 复合索引示例
假设有一个 user
表,创建了如下 复合索引(联合索引):
sql
CREATE INDEX idx_user ON user (name, age, city);
索引顺序:
- 第一列:
name
- 第二列:
age
- 第三列:
city
此时,该索引可以加速如下查询:
✅ 可以使用索引的查询
sql
SELECT * FROM user WHERE name = 'Tom'; -- 只用到了第一列 ✅
SELECT * FROM user WHERE name = 'Tom' AND age = 25; -- 使用了前两列 ✅
SELECT * FROM user WHERE name = 'Tom' AND age = 25 AND city = 'Beijing'; -- 使用了全部索引列 ✅
SELECT * FROM user WHERE name LIKE 'T%'; -- 模糊匹配最左列 ✅
- 以上 SQL 都符合 最左前缀匹配原则 ,因此 MySQL 会使用索引。
❌ 不能使用索引的查询
sql
SELECT * FROM user WHERE age = 25; -- 跳过了第一列 ❌
SELECT * FROM user WHERE city = 'Beijing'; -- 跳过了第一、第二列 ❌
SELECT * FROM user WHERE age = 25 AND city = 'Beijing'; -- 跳过了第一列 ❌
SELECT * FROM user WHERE name LIKE '%T'; -- 以 % 开头 ❌
❌ 索引失效的情况
- 查询条件不包含索引的最左列 (如
age=25
)。 - 跳过索引列 (如
age=25 AND city='Beijing'
,因为name
没有出现,索引无法使用)。 - 最左列使用 % 开头的模糊查询 (如
name LIKE '%T'
,导致索引失效)。 - 在索引列上进行计算、函数操作 (如
WHERE LEFT(name, 2) = 'To'
,因为LEFT()
破坏了索引匹配)。
2. 最左前缀索引的匹配规则
假设索引是 (A, B, C, D)
,查询时:
- 能匹配 A → 可以使用索引 ✅
- 能匹配 A, B → 可以使用索引 ✅
- 能匹配 A, B, C → 可以使用索引 ✅
- 跳过 A,直接匹配 B 或 C → 索引失效 ❌
- 在 A 上使用函数、计算等操作 → 索引失效 ❌
3. 最左前缀匹配优化建议
-
尽量遵循索引的列顺序,避免跳过列。
-
尽量使用 = 或 IN 进行查询,避免索引失效。
-
不要对索引列进行计算或函数操作,否则 MySQL 无法利用索引。
-
如果范围查询 (
>
,<
) 出现在某列,则索引匹配会终止,即:部分失效。如:
sql
SELECT * FROM user WHERE name = 'Tom' AND age > 25 AND city = 'Beijing';
这里索引只能用到 name, age
,但 city
不会被索引,因为 age > 25
,使得 city
失效。
解析:索引匹配顺序:
name = 'Tom'
→ 索引匹配 ✅age > 25
→ 索引匹配 ✅(但是因为是范围查询,后续索引匹配终止!)city = 'Beijing'
→ 索引失效 ❌(不会使用索引)
🔴 为什么 city 列的索引失效?
- MySQL 索引是按照
(name, age, city)
的顺序建立的,索引匹配是按顺序进行的。 - 一旦遇到范围查询(>, <, BETWEEN) ,MySQL 不会继续使用索引后面的列。
age > 25
是一个范围查询,因此 索引匹配到 age 这里就停止了 ,city
不能再用索引。
4. 总结
- 最左列必须出现在查询条件中,否则索引失效!
- 范围查询 (>, <, BETWEEN) 之后的索引列不再生效!
- 索引匹配是按照最左列依次匹配的,中间不能跳过!
📌 牢记 :写 SQL 时要 遵循索引的顺序,才能发挥索引的最大性能!🚀