MySQL 优化之 ICP (index condition pushdown:索引条件下推)

摘要:
p=577对where中过滤条件的处理,根据索引使用情况分成了三种:indexkey,indexfilter,tablefilter1.indexkey用于确定SQL查询在索引中的连续范围的查询条件,被称之为IndexKey。由于一个范围,至少包含一个起始与一个终止,因此IndexKey也被拆分为IndexFirstKey和IndexLastKey,分别用于定位索引查找的起始,以及索引查询的终止条件。而在MySQL5.6之后,IndexFilter与TableFilter分离,IndexFilter下降到InnoDB的索引层面进行过滤,减少了回表与返回MySQLServer层的记录交互开销,提高了SQL的执行效率。所以所谓的ICP技术,其实就是indexfilter技术而已。

ICP技术是在MySQL5.6中引入的一种索引优化技术。它能减少在使用 二级索引 过滤where条件时的回表次数 和 减少MySQL server层和引擎层的交互次数。在索引组织表中,使用二级索引进行回表的代价相比堆表中是要高一些的。相关文档地址:http://dev.mysql.com/doc/refman/5.6/en/index-condition-pushdown-optimization.html

Index Condition Pushdown optimization is used for the range, ref, eq_ref, and ref_or_null access methods when there is a need to access full table rows. This strategy can be used for InnoDB and MyISAM tables. (Note that index condition pushdown is not supported with partitioned tables in MySQL 5.6; this issue is resolved in MySQL 5.7.) For InnoDB tables, however, ICP is used only for secondary indexes. The goal of ICP is to reduce the number of full-record reads and thereby reduce IO operations. For InnoDB clustered indexes(值主键索引), the complete record is already read into the InnoDB buffer. Using ICP in this case does not reduce IO.

要想深入理解 ICP 技术,必须先理解数据库是如何处理 where 中的条件的。具体可以参考何登成博士的文章:http://hedengcheng.com/?p=577

对 where 中过滤条件的处理,根据索引使用情况分成了三种:index key, index filter, table filter

1. index key

用于确定SQL查询在索引中的连续范围(起始范围+结束范围)的查询条件,被称之为Index Key。由于一个范围,至少包含一个起始与一个终止,因此Index Key也被拆分为Index First Key和Index Last Key,分别用于定位索引查找的起始,以及索引查询的终止条件。也就是说根据索引来确定扫描的范围

2. index filter

在使用 index key 确定了起始范围和介绍范围之后,在此范围之内,还有一些记录不符合where 条件,如果这些条件可以使用索引进行过滤,那么就是 index filter。也就是说用索引来进行where条件过滤

3. table filter

where 中的条件不能使用索引进行处理的,只能访问table,进行条件过滤了。

也就是说各种各样的 where 条件,在进行处理时,分成了上面三种情况,一种条件会使用索引确定扫描的范围;一种条件可以在索引中进行过滤;一种必须回表进行过滤;

如何确定哪些where条件分别是 index key, index filter, table filter,可以参考何博士的文章。

在 MySQL5.6 之前,并不区分Index Filter与Table Filter,统统将Index First Key与Index Last Key范围内的索引记录,回表读取完整记录,然后返回给MySQL Server层进行过滤。而在MySQL 5.6之后,Index Filter与Table Filter分离,Index Filter下降到InnoDB的索引层面进行过滤,减少了回表与返回MySQL Server层的记录交互开销,提高了SQL的执行效率。

所以所谓的 ICP 技术,其实就是 index filter 技术而已。只不过因为MySQL的架构原因,分成了server层和引擎层,才有所谓的“下推”的说法。所以ICP其实就是实现了index filter技术,将原来的在server层进行的table filter中可以进行index filter的部分,在引擎层面使用index filter进行处理,不再需要回表进行table filter

4. ICP 技术启用前后比较

To see how this optimization works, consider first how an index scan proceeds when Index Condition Pushdown is not used:

  1. Get the next row, first by reading the index tuple, and then by using the index tuple to locate and read the full table row.

  2. Test the part of the WHERE condition that applies to this table. Accept or reject the row based on the test result.

When Index Condition Pushdown is used, the scan proceeds like this instead:

  1. Get the next row's index tuple (but not the full table row).

  2. Test the part of the WHERE condition that applies to this table and can be checked using only index columns. If the condition is not satisfied, proceed to the index tuple for the next row.

  3. If the condition is satisfied, use the index tuple to locate and read the full table row.

  4. Test the remaining part of the WHERE condition that applies to this table. Accept or reject the row based on the test result.

When Index Condition Pushdown is used, the Extra column in EXPLAIN output shows Using index condition. It will not show Index only because that does not apply when full table rows must be read.

5. ICP 例子

官方文档给出了一个例子:

Suppose that we have a table containing information about people and their addresses and that the table has an index defined as INDEX (zipcode, lastname, firstname). If we know a person's zipcode value but are not sure about the last name, we can search like this:

SELECT * FROMpeople WHERE zipcode='95054' AND lastname LIKE '%etrunia%' AND address LIKE '%Main Street%';

MySQL can use the index to scan through people with zipcode='95054'. The second part (lastname LIKE '%etrunia%') cannot be used to limit the number of rows that must be scanned, so without Index Condition Pushdown, this query must retrieve full table rows for all the people who have zipcode='95054'.

With Index Condition Pushdown, MySQL will check the lastname LIKE '%etrunia%' part before reading the full table row. This avoids reading full rows corresponding to all index tuples that do not match the lastname condition.

Index Condition Pushdown is enabled by default; it can be controlled with the optimizer_switch system variable by setting the index_condition_pushdown flag. See Section 8.9.2, “Controlling Switchable Optimizations”.

上面例子中的 lastername like '%etrunia%' 和 address like '%Main Street%' 本来是无法使用复合索引 index(zipcode, lastername, firstname) 进行过滤的,但是因为有了ICP技术,所以他们可以在 index filter 阶段使用索引进行过滤,无需回表进行 table filter.

例子2:

role_goods 表上有组合索引 index(roleId,status,number),下面的select语句,因为 “索引最左前缀原则”,只能使用到 组合索引的 roleId 部分,但是因为 ICP 技术的存在,现在 number 条件过滤也可以在 index filter 阶段完成了,无需像以前一样需要进行 table filer 了:

mysql> explain select * from role_goods where roleId=100000001 and number=1;
+----+-------------+------------+------+---------------+----------+---------+-------+------+-----------------------+
| id | select_type | table      | type | possible_keys | key      | key_len | ref   | rows | Extra                 |
+----+-------------+------------+------+---------------+----------+---------+-------+------+-----------------------+
|  1 | SIMPLE      | role_goods | ref  | roleId_2      | roleId_2 | 9       | const |   14 | Using index condition |
+----+-------------+------------+------+---------------+----------+---------+-------+------+-----------------------+
1 row in set (0.01 sec)

可以看到 key_len = 9, 因为 roleId 是big int 类型,所以 key_len = 8 + 1 = 9; 所以在 index key 阶段中,并没有使用到 组合索引 index(roleId,status,number) 中的 number 字段(因为中间有一个status字段没有出现在where 条件中),但是 “Using index condition” 却说明使用到了ICP技术,显然是 number =1 条件过滤使用到了ICP技术。

参考:

http://hedengcheng.com/?p=577

http://dev.mysql.com/doc/refman/5.6/en/index-condition-pushdown-optimization.html

免责声明:文章转载自《MySQL 优化之 ICP (index condition pushdown:索引条件下推)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇无法使用MSHFLXGD.OCX控件的一个解决办法KVM虚拟化简介及安装下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

docker部署禅道及开启MySQL远程登录

禅道作为一个开源的项目管理工具,其功能足以满足日常开发、运维、测试及产品版本迭代,重要的是免费、可定制,好处不用多数,业内用的也比较广泛(主要是互联网企业) 关于禅道的部署可以参考官网:https://www.zentao.net/book/zentaopmshelp/405.html 有了docker,使得禅道的部署变得非常简单,只需如下几个步骤即可完成...

SQLi-Labs:Less54-Less65

从54关开始,开始慢慢偏向于实际环境,加了次数限制之类的 Less 54 本关中是对输入的次数做了限制,必须在10次请求之内获取信息,否则会刷新表名 首先判断了单引号闭合 ?id=1'  判断有三列 ?id=1' order by 3--+  爆库 ?id=-1' union select 1,database(),3--+   爆表 ?id=-1'...

innobackupex备份命令输出

通过屏幕输出了解备份过程 首先读取my.cnf 文件,找到参数配置和数据目录等 备份innodb文件 加锁 开始备份非innodb文件 190613 16:40:06 Executing FLUSH NO_WRITE_TO_BINLOG TABLES...190613 16:40:06 Executing FLUSH TABLES WITH READ LO...

mysql select 拼接字段结果CONCAT和CONCAT_WS

CONCAT(str1,str2,...) 将参数连接成字符串返回。如果有任何一个参数为 NULL,返回值也为 NULL。可以有超过 2 个的参数。数字参数将被转换为相等价的字符串形式: mysql> SELECT CONCAT( 'My ', 'S ', 'QL '); -> 'MySQL ' mysql> SELECT CONCAT(...

MyBatis(三)全局配置文件 之 databaseProvider 数据库厂商标识

databaseIdProvider环境一、databaseIdProvider 属性 MyBatis可以根据不同的数据库厂商执行不同的语句 <databaseIdProvider type="DB_VENDOR"> <!-- 为不同的数据库厂商起别名 --> <property name="M...

连接MySQL报 unblock with 'mysqladmin flush-hosts' 问题解决

    工作中突然遇到有一台服务器连接不上MySQL数据库,报错如下,其他服务都正常。特此总结一下解决方法。 可以看出,产生的原因是: 同一个ip在短时间内产生太多(超过mysql数据库max_connect_errors的最大值)中断的数据库连接而导致的阻塞 max_connect_errors是一个MySQL中与安全有关的计数器值,它负责阻止过多尝试...