详细解析 MySQL 性能优化之【索引下推】

基础概念

索引下推(Index Pushdown, ICP) 是数据库查询优化中的一种核心技术,用于减少回表次数、提升查询效率,尤其适用于联合索引场景。

索引下推是指:数据库在遍历索引时,提前过滤掉不满足查询条件的记录,只将符合条件的记录回表获取完整数据

简单来说,就是在索引层面完成部分 WHERE 过滤,而非全部等到回表后再过滤

索引下推就是将原本应该在Server层执行的任务下推到引擎层执行。

不使用索引下推

这是 MySQL 在未开启 ICP 优化时的传统查询流程。

1)索引扫描与定位

  1. MySQL 查询优化器决定使用某个索引来执行查询。
  2. 存储引擎开始扫描该索引,逐条读取索引记录。索引记录中包含索引列的值以及对应的主键(或指向数据行的指针)。

2)回表

对于每一条从索引中找到的记录,存储引擎立即 使用其中的主键值去主键索引(聚簇索引)中查找并读取完整的行数据。这个过程就是 "回表"。

3)Server 层过滤

  1. 存储引擎将读取到的完整行数据返回给 MySQL 的 Server 层。
  2. Server 层接收到完整行后,再根据 WHERE 子句中的所有条件对该行数据进行过滤。
  3. 如果满足条件,则将其加入结果集;如果不满足,则丢弃。

核心特点: 索引仅用于快速定位到可能的行,但所有 WHERE 条件的过滤工作都在 Server 层完成。这意味着,即使某些 WHERE 条件可以通过索引列判断,数据库也必须先把完整的行拉取出来才能进行判断。

使用索引下推

ICP 是一种优化,它允许存储引擎在扫描索引的同时,提前过滤掉一部分不符合条件的数据,从而减少回表次数。

1)索引扫描

同样,优化器决定使用某个索引,存储引擎开始扫描该索引,逐条读取索引记录。

2)存储引擎内过滤

  1. 在读取了一条索引记录后,存储引擎不会立即去回表。
  2. 它会检查 WHERE 子句中,是否有可以利用当前索引中的列进行判断的条件
  3. 如果存在这样的条件,存储引擎会在存储引擎层内部直接用索引记录中的值对该条件进行判断。

如果判断结果不满足条件:存储引擎会直接丢弃这条索引记录,不再进行后续的回表操作,而是直接处理下一条索引记录。

如果判断结果满足条件 :说明这条索引记录对应的完整行有可能是符合查询要求的,才会进入下一步。

3)回表

只有通过了存储引擎内部过滤的索引记录,存储引擎才会使用其主键值去回表,读取完整的行数据。

4)Server 层最终过滤

  1. 存储引擎将完整的行数据返回给 Server 层。
  2. Server 层会对该行数据进行最后的检查,以满足 WHERE 子句中那些无法在存储引擎层利用索引进行过滤的剩余条件(例如,过滤条件涉及非索引列,或者是函数操作等)。
  3. 最终决定是否将该行加入结果集。

核心特点: 一部分 WHERE 过滤工作被 "下推" 到了存储引擎层,并利用索引中的数据提前完成。这减少了不必要的回表操作,因为那些明显不满足部分 WHERE 条件的记录在索引扫描阶段就被过滤掉了,根本不会去读取完整行。

实例

这是一个基础的学生信息表,我设立了**(name, age)**的联合索引。

这是索引树叶子节点具体的数据图,接下来从图出发说明用ICP和不用ICP的区别。

select语句为:SELECT * FROM students_contact WHERE name LIKE '张%'AND age > 18;

不用ICP

范围查询之后的索引会失效,所以生效的索引只有name LIKE '张%'。因此联合索引拿到数据后会不断回表查询,获得所有符合张%的数据,然后再返回server层对age > 18进行筛选。

最终过滤出来只有张三一条是符合条件的,上述过程联合索引的字段age是没有任何作用的。

使用ICP

存储引擎根据(name,age)联合索引,找到name LIKE '张%',由于联合索引中包含age列,所以存储引擎直接再联合索引里按照age > 18过滤。按照过滤后的数据再一一进行回表扫描。

可以看到,如果使用索引下推的话,只需要一次回表,在存储引擎层面就可以根据联合索引筛选出想要的数据。

我们同样也可以使用Explain来验证我们的想法。

EXPLAIN SELECT * FROM students_contact

WHERE name LIKE '张%' -- 1. 索引前缀范围扫描

AND age > 18 -- 2. 索引内非前缀条件 (ICP 过滤)

可以从执行计划看到,Extra 中显示 Using index condition,即使用了联合索引。

注意如果发现一直没有用上索引下推,需要检查下功能是否被禁用,默认是打开的。可以通过设置系统变量optimizer_switch控制:index_condition_pushdown。

复制代码
# 打开索引下推 SET optimizer_switch = 'index_condition_pushdown=on'; 
# 关闭索引下推 SET optimizer_switch = 'index_condition_pushdown=off';

适用场景

  1. 联合索引 :必须是多列索引,且过滤条件包含索引中非前缀的列(如上述例子中的 agecity)。
  2. 非前缀匹配查询 :如 LIKE '张%'(前缀匹配)+ 其他列过滤,或范围查询(age > 20)。
  3. 回表代价高:当索引前缀匹配到大量记录时,ICP 能显著减少回表次数。
相关推荐
想摆烂的不会研究的研究生13 小时前
每日八股——Redis(1)
数据库·经验分享·redis·后端·缓存
码熔burning13 小时前
MySQL 8.0 新特性爆笑盘点:从青铜到王者的骚操作都在这儿了!(万字详解,建议收藏)
数据库·mysql
猫头虎13 小时前
2025最新OpenEuler系统安装MySQL的详细教程
linux·服务器·数据库·sql·mysql·macos·openeuler
哈库纳玛塔塔14 小时前
放弃 MyBatis,拥抱新一代 Java 数据访问库
java·开发语言·数据库·mybatis·orm·dbvisitor
eason_fan15 小时前
Service Worker 缓存请求:前端性能优化的进阶利器
前端·性能优化
@LetsTGBot搜索引擎机器人15 小时前
2025 Telegram 最新免费社工库机器人(LetsTG可[特殊字符])搭建指南(含 Python 脚本)
数据库·搜索引擎·机器人·开源·全文检索·facebook·twitter
计算机毕设VX:Fegn089516 小时前
计算机毕业设计|基于springboot + vue动物园管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
冉冰学姐16 小时前
SSM校园排球联赛管理系统y513u(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面
数据库·ssm 框架应用·开题报告、
Tony Bai17 小时前
【分布式系统】03 复制(上):“权威中心”的秩序 —— 主从架构、一致性与权衡
大数据·数据库·分布式·架构
wb0430720118 小时前
SQL工坊不只是一个ORM框架
数据库·sql