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

文章目录


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


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

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

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

但很多时候,你明明建了索引,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 条实战准则》

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


相关推荐
小白学大数据1 分钟前
Java 爬虫对百科词条分类信息的抓取与处理
java·开发语言·爬虫
此生只爱蛋7 分钟前
【Redis】Set 集合
数据库·redis·缓存
bjzhang7519 分钟前
C#操作SQLite数据库
数据库·sqlite·c#
zmzb010319 分钟前
C++课后习题训练记录Day56
开发语言·c++
编程小Y22 分钟前
C++ Insights
开发语言·c++
hans汉斯29 分钟前
嵌入式操作系统技术发展趋势
大数据·数据库·物联网·rust·云计算·嵌入式实时数据库·汉斯出版社
小c君tt39 分钟前
QT中想在QTextEdit控件中使用Qslog日志输出出现问题原因及解决方法
开发语言·qt
Coder_Boy_1 小时前
Spring 核心思想与企业级最佳特性(实践级)事务相关
java·数据库·spring
+VX:Fegn08951 小时前
计算机毕业设计|基于springboot + vue宠物寄养系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计·宠物
历程里程碑1 小时前
hot 206
java·开发语言·数据结构·c++·python·算法·排序算法