mysql索引下推

索引下推

索引下推(Index Condition Pushdown) ICP 是Mysql5.6之后新增的功能,主要的核心点就在于把数据筛选的过程放在了存储引擎层去处理,而不是像之前一样放到Server层去做过滤。
虽然这是一个比较简单的概念,但是可能很多不细心的同学对于索引下推会存在一个小小的误区,至于是什么,请看下文。
什么是索引下推

首先,我们创建一张 t_test表,同时建立age_name的联合索引,同时插入3条测试数据。

CREATE TABLE `t_test` (
  `id` bigint NOT NULL,
  `age` int NOT NULL,
  `name` varchar(100) NOT NULL,
  `class` varchar(100),
	
  PRIMARY KEY (`id`),
   KEY `age_name` (`age`,`name`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

然后,我们执行查询explain SELECT * from t_test where age >10 and name = ‘a’,如下图所示,就会看见Extra中显示了Using index condition,你可能就知道了,这表示出现了索引下推了(不是联合索引也会出现,索引下推只是针对联合索引的)。
在这里插入图片描述

没错,针对这个查询场景就是索引下推,那到底什么是索引下推呢?
按照我们上述的场景,实际上就存在两个索引树,一个是主键索引,存储了具体的数据的信息,另外则是age_name的联合索引,保存了主键的ID。
图片

在没有ICP索引下推的时候,这个查询的流程应该是这样(略过无关的细节):
Mysql Server层调用API查询存储引擎数据
存储引擎根据联合索引首先通过条件找到所有age>10的数据
找到的每一条数据都根据主键索引进行回表查询,直到找到不符合条件的结果
返回数据给Server层,Server根据条件对结果进行过滤,流程结束
而有了ICP之后的流程则是这样:
Mysql Server层调用API查询存储引擎数据
存储引擎根据联合索引首先通过条件找到所有age>10的数据,根据联合索引中已经存在的name数据进行过滤,找到符合条件的数据
根据找到符合条件的数据,回表查询
返回数据给Server层,流程结束
对比这两个流程就会很明显的发现,使用ICP之后我们就是简单的通过联合索引中本来就有的数据直接过滤了,不需要再查到一堆无用的数据去Server层进行过滤,这样的话减少了回表的次数和返回的数据,IO次数减少了,对性能有很好的提升。
按照官方文档所说,ICP其实也存在一定的使用限制场景,只说关键的,乱七八糟的不说。
首先,ICP适用于range、ref、eq_ref和ref_or_null的场景下
InnoDB和MyISAM都支持ICP,Mysql partition分表的话也可以使用
对于InndoDB而言,ICP只支持二级索引,因为主键索引它用不上不是吗?
子查询不支持
现在我们基本都使用的5.6以上的版本了,默认就是开启ICP的,想关闭的话可以通过命令SET optimizer_switch = ‘index_condition_pushdown=off’;。
一个小小的误区

一般来说,正常情况下Mysql一次查询都只能走一个索引,我们来修改上述的表结构,把联合索引改为两个单独的索引,数据保持不变

CREATE TABLE `t_test` (
  `id` bigint NOT NULL,
  `age` int NOT NULL,
  `name` varchar(100) NOT NULL,
  `class` varchar(100),
	
  PRIMARY KEY (`id`),
   KEY `age_index` (`age`) USING BTREE,
   KEY `name_index` (`name`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

然后我们执行查询explain SELECT * from t_test where age >10 and name like ‘a%’,结果如下图。
在这里插入图片描述

你会发现,我靠,怎么还有索引下推?这不科学对不对,好像无法解释嘛,难道这一次索引下推还能先查出age再下推到name索引吗,这完全不合理啊。
其实不然,真实的情况是,Using index condition并不代表一定是使用了索引下推,只是代表可以使用,但是不一定用了。。。
这个就有点坑爹,可能会对我们判断的时候造成误解啊。
如果你去网上搜很多人举例子这样建索引,然后告诉你这就是索引下推的时候,你可以尽情的喷他了,我们说索引下推一定是在联合索引的情况下,根据联合索引本身就有的数据直接做一次过滤,而不用再进行多次无用的回表再到Server层进行过滤,这一点你要很明确才行。

<think>嗯,我现在需要理解MySQL索引下推(Index Condition Pushdown,ICP)的工作原理和应用场景。首先,我记得ICP是MySQL中的一种优化技术,但具体是怎么工作的呢?可能和索引的使用有关,但不确定细节。 根据用户提供的引用资料,引用[1]提到ICP是5.6版本引入的优化,可能涉及到将WHERE条件的一部分下推到存储引擎层处理。那存储引擎通常负责索引的扫描,所以可能是在索引扫描阶段就应用某些条件,减少回表次数? 比如,用户提供的引用[3]中的EXPLAIN输出显示Extra列有“Using index condition”和“Using where”,这可能意味着存储引擎层处理了一部分条件,而服务器层处理剩下的。这样是不是可以减少从存储引擎返回到服务器层的数据量? 再来看引用[4]和[5],当使用ICP时,Extra列显示“Using index condition”,而如果关闭ICP(如引用[2]的设置),可能就不会有这个提示了。这说明ICP的状态会影响查询的执行计划。 那具体来说,假设有一个复合索引(first_name, last_name),查询条件是first_name = 'John' AND last_name LIKE '%son%' AND age > 30。在ICP开启的情况下,存储引擎会先通过索引处理first_name和last_name的条件,但age列可能不在索引中。这时候,存储引擎只能处理索引中的条件(比如last_name的LIKE),而age的条件需要在服务器层处理。但如果没有ICP,存储引擎可能只会处理first_name的条件,然后将所有匹配first_name的记录返回给服务器层,再由服务器处理last_name和age的条件。这样的话,如果last_name的条件在索引中可以部分应用,就能减少回表次数,提升性能。 另一个例子是范围查询。如果有索引(a, b, c),查询条件是a=1 AND b BETWEEN 10 AND 20 AND c=5。存储引擎可能先定位a=1的索引条目,然后在索引中处理b的范围条件,这时候即使c不在索引中被处理,但ICP可能允许在索引中处理b的条件,从而减少需要访问的数据行数。 应用场景的话,可能是在复合索引的情况下,尤其是当WHERE子句中有部分条件可以利用索引中的列,但这些条件不能完全用索引来覆盖的时候。比如,当有LIKE操作或者范围条件,索引下推可以将这些条件下推到存储引擎处理,减少回表次数,提高查询效率。 性能优化方面,开启ICP可以减少服务器层需要处理的数据量,从而减少IO和CPU消耗。不过需要注意,可能不是所有情况下都适用,比如如果索引的选择性不高,或者大部分数据都需要被返回,可能效果不明显。另外,需要检查EXPLAIN的输出是否有“Using index condition”来确认ICP是否被使用。 可能的问题还有,ICP和覆盖索引的关系?如果查询的列都在索引中,可能不需要回表,此时ICP是否还有作用?比如,如果查询的列全部在索引中,存储引擎可能已经处理了所有条件,但如果是覆盖索引的情况下,可能ICP的作用可能不大,因为不需要回表,但如果有条件在索引中被处理,可能仍然可以提前过滤数据。 总结一下,ICP的工作原理是允许存储引擎在扫描索引时提前应用WHERE子句中的部分条件,从而减少需要回表读取的数据行数,进而提升查询性能。应用场景主要是在复合索引中,存在可以利用索引列的条件但无法完全被索引覆盖的情况。性能优化方面,开启ICP可以显著减少IO和CPU开销,尤其是在高选择性查询中效果明显。</think>### MySQL索引下推(ICP)工作原理与性能优化 #### 1. 工作原理 索引下推(Index Condition Pushdown, ICP)是MySQL 5.6引入的优化技术,**核心目标是通过减少回表次数提升查询性能**。其工作原理如下: - **传统方式**:存储引擎仅根据索引的**最左前缀**筛选数据,剩余WHERE条件由服务器层处理。例如,索引$(a, b)$,查询条件为$a=1 \land b>5$,存储引擎仅筛选$a=1$的记录,服务器再过滤$b>5$[^1]。 - **ICP优化**:存储引擎在扫描索引时,直接应用WHERE条件中**索引包含的列**(即使不满足最左前缀)。例如,索引$(a, b)$,查询条件为$a=1 \land b>5 \land c=3$,存储引擎会筛选$a=1 \land b>5$,仅返回满足条件的记录给服务器层,最后再由服务器处理$c=3$[^4]。 #### 2. 应用场景 - **复合索引的部分条件过滤** 当查询条件包含索引列和非索引列时,ICP可将索引列的过滤下推。例如: ```sql SELECT * FROM employees WHERE first_name = 'John' AND last_name LIKE '%son%' AND age > 30; -- 假设索引为 (first_name, last_name) ``` 存储引擎会处理`first_name = 'John'`和`last_name LIKE '%son%'`,减少回表后再过滤`age > 30`的数据量[^3]。 - **范围查询优化** 若查询包含范围条件(如`BETWEEN`, `>`),ICP允许在索引中提前过滤。例如: ```sql SELECT * FROM table WHERE a = 1 AND b BETWEEN 10 AND 20 AND c = 5; -- 索引为 (a, b, c) ``` 存储引擎直接处理`a=1`和`b`的范围条件,无需将所有`a=1`的记录返回服务器[^5]。 #### 3. 性能优化效果 - **减少回表次数**:存储引擎提前过滤数据,减少需要访问的主键索引记录数。 - **降低服务器层负载**:通过减少数据传输量,降低CPU和内存消耗。 - **EXPLAIN验证**:若Extra列显示`Using index condition`,说明ICP已生效。 #### 4. 配置与限制 - **启用/关闭ICP**: ```sql SET optimizer_switch = 'index_condition_pushdown=on|off'; -- 引用[2] ``` - **适用存储引擎**:InnoDB和MyISAM。 - **限制条件**:仅适用于二级索引(非主键索引),且需要满足索引列的条件过滤。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值