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

文章目录


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


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

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

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

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

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


相关推荐
沛沛老爹3 分钟前
Web转AI架构篇 Agent Skills vs MCP:工具箱与标准接口的本质区别
java·开发语言·前端·人工智能·架构·企业开发
码农小卡拉8 分钟前
Maven与Gradle选型指南:如何匹配项目的依赖管理需求
java·gradle·maven
avi911111 分钟前
Unity 天命6源码- 商业游戏说明分析
开发语言·unity·c#·游戏开发·游戏源码
黎雁·泠崖11 分钟前
吃透Java操作符进阶:算术+移位操作符 全解析(Java&C区别+完整案例+避坑指南)
java·c语言·python
ZKNOW甄知科技14 分钟前
IT自动分派单据:让企业服务流程更智能、更高效的关键技术
大数据·运维·数据库·人工智能·低代码·自动化
低频电磁之道36 分钟前
编译C++的几种方式(MSVC编译器)
开发语言·c++
小光学长40 分钟前
基于Web的长江游轮公共服务系统j225o57w(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
前端·数据库
Zsy_05100342 分钟前
【C++】类和对象(一)
开发语言·c++
Yu_iChan1 小时前
Day10 用户端订单模块
java