联合索引的最左前缀原则与失效场景

文章目录


《联合索引的最左前缀原则与失效场景》


一、前言:索引不总是生效的

大家好,我是程序员卷卷狗。

我们都知道给字段建索引能提高查询速度,

但很多时候,你明明建了索引,SQL 却依然走全表扫描。

面试官问:

"联合索引的最左前缀原则是什么?"

"为什么有时候用了 LIKE、OR、函数就失效了?"

要答好这个问题,必须先理解:
联合索引的底层结构是有序的前缀匹配树。


二、联合索引的结构

假设我们创建一个三列联合索引:

sql 复制代码
CREATE INDEX idx_name_age_city ON user(name, age, city);

InnoDB 会在 B+ 树的叶子节点中存储:

复制代码
(name, age, city, 主键id)

索引的排序方式如下:

复制代码
先按 name 排序,
name 相同时按 age 排序,
name 和 age 都相同时按 city 排序。

可以理解为一张"有序排列表"

name age city
Alice 20 Beijing
Alice 22 Shanghai
Bob 19 Beijing
Bob 23 Chengdu

三、最左前缀原则的核心

定义:

MySQL 使用联合索引时,会从最左边的索引列开始匹配,

一旦遇到范围查询、模糊匹配或非连续字段,就停止匹配。

(1)完整匹配(命中索引)
sql 复制代码
WHERE name='Alice' AND age=20 AND city='Beijing'

命中三列,索引完全使用。

(2)前缀匹配(部分命中)
sql 复制代码
WHERE name='Alice' AND age=20

命中前两列,仍能使用索引。

(3)仅最左列匹配
sql 复制代码
WHERE name='Alice'

命中第一列,索引可用。

(4)跳列查询(失效)
sql 复制代码
WHERE age=20 AND city='Beijing'

name 被跳过,索引无法命中。

规则总结:

  • 从左向右连续匹配;
  • 一旦中断,后续字段无法使用。

四、常见索引失效场景

1. 范围查询(>、<、BETWEEN、LIKE)中断匹配
sql 复制代码
WHERE name='Alice' AND age>20 AND city='Beijing';
  • name 精确匹配 ;
  • age 为范围匹配(>20);
  • city 失效。

范围条件之后的字段不再使用索引。


2. 模糊匹配前缀失效
sql 复制代码
WHERE name LIKE '%lice';

无法利用索引(前缀未知)。

sql 复制代码
WHERE name LIKE 'A%';

能利用索引(前缀已知)。


3. 函数操作导致失效
sql 复制代码
WHERE LEFT(name,3)='Ali';

索引失效,因为函数作用在列上。

改写方式:

sql 复制代码
WHERE name LIKE 'Ali%';

4. 隐式类型转换失效
sql 复制代码
WHERE age = '20';

若 age 为 INT,而 '20' 为字符串,会发生隐式转换:

sql 复制代码
CAST(age AS CHAR) = '20';

索引失效。

改写:

sql 复制代码
WHERE age = 20;

5. OR 条件混合失效
sql 复制代码
WHERE name='Alice' OR city='Beijing';

若 city 未建立独立索引,则整体失效。

改写:

  • 为 city 单独建索引;
  • 或用 UNION ALL 拆分查询。

6. 计算表达式失效
sql 复制代码
WHERE age + 1 = 20;

索引失效,因为表达式作用在列上。

改写:

sql 复制代码
WHERE age = 19;

五、Explain 实战验证

假设表结构:

sql 复制代码
CREATE TABLE user (
  id INT PRIMARY KEY,
  name VARCHAR(20),
  age INT,
  city VARCHAR(20),
  INDEX idx_name_age_city (name, age, city)
);
SQL 结果 Extra
SELECT * FROM user WHERE name='Alice'; 索引生效 Using index condition
SELECT * FROM user WHERE name='Alice' AND age>20; 部分命中 Using index condition
SELECT * FROM user WHERE age=20; 索引失效 Using where
SELECT * FROM user WHERE name LIKE 'A%'; 索引生效 Using index condition
SELECT * FROM user WHERE name LIKE '%A'; 失效 Using where
SELECT * FROM user WHERE name='Alice' AND age=20 AND city='Beijing'; 完全命中 Using index

六、索引设计与优化建议

设计策略 原则说明
① 建联合索引时把区分度高的字段放前面 提升过滤率
② WHERE、ORDER BY、GROUP BY 常用字段放在前缀位置 利用最左原则
③ 尽量避免函数、计算、类型转换 防止优化器放弃索引
④ 模糊匹配尽量使用后缀 % 而非前缀 % 支持前缀匹配
⑤ 使用 EXPLAIN 验证索引命中情况 判断 type、key、Extra

七、面试高频问题与答题模板

问题 答案要点
Q1:什么是最左前缀原则? 联合索引按定义顺序匹配字段,从最左开始连续使用。
Q2:为什么范围查询会导致后续字段失效? 因为 B+Tree 有序性被破坏,无法继续匹配。
Q3:LIKE '%xx' 能用索引吗? 不能,前缀未知。
Q4:为什么函数会导致索引失效? 函数在列上操作,破坏原索引值。
Q5:OR 条件一定导致失效吗? 若两侧字段都有索引则不会,否则整体失效。
Q6:如何验证索引是否命中? 使用 EXPLAIN 查看 key 与 Extra 字段。

八、总结

联合索引的本质是一棵按列顺序排列的有序 B+ 树。

最左前缀原则,是优化器决定是否能使用索引的根规则。

一句话记住:

匹配从左开始,遇"断"即停。

掌握这一原则,你不仅能解释索引失效的原因,

还能主动在表设计和 SQL 编写中"避坑提速"。

下一篇(第 9 篇),我将写------
《索引优化策略:高效建索引的 7 条实战准则》

总结从索引区分度、联合索引布局、覆盖索引设计到业务性能调优的完整策略。


相关推荐
纪莫2 小时前
技术面:SpringCloud(SpringCloud有哪些组件,SpringCloud与Dubbo的区别)
java·spring·java面试⑧股
2739920292 小时前
qInstallMessageHandler(重定向至log文件)
开发语言·qt
yddddddy2 小时前
关于vue3
开发语言·vue
会编程的吕洞宾2 小时前
Java中的“万物皆对象”:一场编程界的哲学革命
java·后端
会编程的吕洞宾2 小时前
Java封装:修仙界的"护体罡气"
java·后端
豆沙沙包?2 小时前
2025年--Lc231-350. 两个数组的交集 II-Java版
java·开发语言
whm27772 小时前
Visual Basic创建工具栏
开发语言·visual studio
程序猿20232 小时前
Python每日一练---第九天:H指数
开发语言·python