ICP(index condition pushdown)是mysql利用索引(二级索引)元组和筛字段在索引中的where条件从表中提取数据记录的一种优化操作。ICP的思想是:存储引擎在访问索引的时候检查筛选字段在索引中的where条件(pushed index condition,推送的索引条件),如果索引元组中的数据不满足推送的索引条件,那么就过滤掉该条数据记录。ICP(优化器)尽可能的把index condition的处理从server层下推到storage engine层。storage engine使用索引过过滤不相关的数据,仅返回符合index condition条件的数据给server层。也是说数据过滤尽可能在storage engine层进行,而不是返回所有数据给server层,然后后再根据where条件进行过滤。使用ICP(mysql 5.6版本以前)和没有使用ICP的数据访问和提取过程如下(插图来在MariaDB Blog)

优化器没有使用ICP时,数据访问和提取的过程如下:

1)    当storage engine读取下一行时,首先读取索引元组(index tuple),然后使用索引元组在基表中(base table)定位和读取整行数据。

2)    sever层评估where条件,如果该行数据满足where条件则使用,否则丢弃。

3)    执行1),直到最后一行数据。

优化器使用ICP时,server层将会把能够通过使用索引进行评估的where条件下推到storage engine层

数据访问和提取过程如下:

1)    storage engine从索引中读取下一条索引元组。

2)    storage engine使用索引元组评估下推的索引条件。如果没有满足where条件,storage engine将会处理下一条索引元组(回到上一步)。只有当索引元组满足下推的索引条件的时候,才会继续去基表中读取数据。

3)    如果满足下推的索引条件,storage engine通过索引元组定位基表的行和读取整行数据并返回给server层。

4)    server层评估没有被下推到storage engine层的where条件,如果该行数据满足where条件则使用,否则丢弃。

而使用ICP时,如果where条件的一部分能够通过使用索引中的字段进行评估,那么mysql server把这部分where条件下推到storage engine(存储引擎层)。存储引擎通过索引元组的索引列数据过滤不满足下推索引条件的数据行。

索引条件下推的意思就是筛选字段在索引中的where条件从server层下推到storage engine层,这样可以在存储引擎层过滤数据。由此可见,ICP可以减少存储引擎访问基表的次数和mysql server访问存储引擎的次数。

注意一下ICP的使用条件:
1.只能用于二级索引(secondary index)。
2.explain显示的执行计划中type值(join 类型)为range、 ref、 eq_ref或者ref_or_null。且查询需要访问表的整行数据,即不能直接通过二级索引的元组数据获得查询结果(索引覆盖)。
3.ICP可以用于MyISAM和InnnoDB存储引擎,不支持分区表(5.7将会解决这个问题)。

ICP的开启优化功能与关闭

MySQL5.6可以通过设置optimizer_switch([global|session],dynamic)变量开启或者关闭index_condition_push优化功能,默认开启。

mysql > set optimizer_switch='index_condition_pushdown=on|off'

用explain查看执行计划时,如果执行计划中的Extra信息为"using index condition",表示优化器使用的index condition pushdown。

在mysql5.6以前,还没有采用ICP这种查询优化,where查询条件中的索引条件在某些情况下没有充分利用索引过滤数据。假设一个组合索引(多列索引)K包含(c1,c2,…,cn)n个列,如果在c1上存在范围扫描的where条件,那么剩余的c2,…,cn这n-1个上索引都无法用来提取和过滤数据(不管不管是唯一查找还是范围查找),索引记录没有被充分利用。即组合索引前面字段上存在范围查询,那么后面的部分的索引将不能被使用,因为后面部分的索引数据是无序。比如,索引key(a,b)中的元组数据为(0,100)、(1,50)、(1,100) ,where查询条件为 a < 2 and b = 100。由于b上得索引数据并不是连续区间,因为在读取(1,50)之后不再会读取(1,100),mysql优化器在执行索引区间扫描之后也不再扫描组合索引其后面的部分。

接下来我们来看看一个例子:

mysql> select version();
+-------------+
| version() |
+-------------+
| 5.5.25a-log |
+-------------+
1 row in set (0.00 sec) mysql>
mysql> show create table rental\G
*************************** 1. row ***************************
Table: rental
Create Table: CREATE TABLE `rental` (
`rental_id` int(11) NOT NULL AUTO_INCREMENT,
`rental_date` datetime NOT NULL,
`inventory_id` mediumint(8) unsigned NOT NULL,
`customer_id` smallint(5) unsigned NOT NULL,
`return_date` datetime DEFAULT NULL,
`staff_id` tinyint(3) unsigned NOT NULL,
`last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`rental_id`),
UNIQUE KEY `rental_date` (`rental_date`,`inventory_id`,`customer_id`),
KEY `idx_fk_inventory_id` (`inventory_id`),
KEY `idx_fk_customer_id` (`customer_id`),
KEY `idx_fk_staff_id` (`staff_id`),
CONSTRAINT `fk_rental_customer` FOREIGN KEY (`customer_id`) REFERENCES `customer` (`customer_id`) ON UPDATE CASCADE,
CONSTRAINT `fk_rental_inventory` FOREIGN KEY (`inventory_id`) REFERENCES `inventory` (`inventory_id`) ON UPDATE CASCADE,
CONSTRAINT `fk_rental_staff` FOREIGN KEY (`staff_id`) REFERENCES `staff` (`staff_id`) ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=16050 DEFAULT CHARSET=utf8
1 row in set (0.03 sec) mysql>

在没有使用ICP情况下的查询:

mysql> explain select * from rental where rental_date = '2006-02-14 15:16:03' and customer_id >= 300 and customer_id <= 400;
+----+-------------+--------+------+--------------------------------+-------------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+------+--------------------------------+-------------+---------+-------+------+-------------+
| 1 | SIMPLE | rental | ref | rental_date,idx_fk_customer_id | rental_date | 8 | const | 181 | Using where |
+----+-------------+--------+------+--------------------------------+-------------+---------+-------+------+-------------+
1 row in set (0.00 sec) mysql>

优化器首先使用复合索引rental_date的首字段rental_date过滤出符合条件rental_date='2006-02-14 15:16:03'的记录(执行计划中key字段显示rental_date),然后根据复合索引rental_date回表获取记录后,最终根据条件customer_id >= 300 and customer_id <= 400来过滤出最后的查询结果(执行计划中Extra字段显示为Using where)

下面看看开启ICP的情况(MySQL 5.6支持)

mysql> select version();
+-----------+
| version() |
+-----------+
| 5.6.10 |
+-----------+
1 row in set (0.01 sec) mysql>
mysql> explain select * from rental where rental_date = '2006-02-14 15:16:03' and customer_id >= 300 and customer_id <= 400;
+----+-------------+--------+------+--------------------------------+-------------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+------+--------------------------------+-------------+---------+-------+------+-----------------------+
| 1 | SIMPLE | rental | ref | rental_date,idx_fk_customer_id | rental_date | 5 | const | 181 | Using index condition |
+----+-------------+--------+------+--------------------------------+-------------+---------+-------+------+-----------------------+
1 row in set (0.00 sec) mysql>

Using index condition 就表示MySQL使用了ICP来优化查询,在检索的时候把条件customer_id的过滤操作下推到存储引擎层来完成。这样能降低不必要的IO访问。

1.首先存储引擎根据条件rental_date = '2006-02-14 15:16:03'和customer_id >= 300 and customer_id <= 400来过滤索引,在索引上过滤customer_id条件

2.根据索引过滤后的记录获取数据

参考资料

http://olavsandstaa.blogspot.co.uk/2011/04/mysql-56-index-condition-pushdown.html

https://mariadb.com/kb/en/index-condition-pushdown/

MySQL 5.6 Index Condition Pushdown的更多相关文章

  1. 浅析MySQL中的Index Condition Pushdown (ICP 索引条件下推)和Multi-Range Read(MRR 索引多范围查找)查询优化

    本文出处:http://www.cnblogs.com/wy123/p/7374078.html(保留出处并非什么原创作品权利,本人拙作还远远达不到,仅仅是为了链接到原文,因为后续对可能存在的一些错误 ...

  2. MySQL 查询优化之 Index Condition Pushdown

    MySQL 查询优化之 Index Condition Pushdown Index Condition Pushdown限制条件 Index Condition Pushdown工作原理 ICP的开 ...

  3. 【mysql】关于Index Condition Pushdown特性

    ICP简介 Index Condition Pushdown (ICP) is an optimization for the case where MySQL retrieves rows from ...

  4. MySQL索引与Index Condition Pushdown

    实际上,这个页面所讲述的是在MariaDB 5.3.3(MySQL是在5.6)开始引入的一种叫做Index Condition Pushdown(以下简称ICP)的查询优化方式.由于本身不是一个层面的 ...

  5. MySQL ICP(Index Condition Pushdown)特性

    一.SQL的where条件提取规则 在ICP(Index Condition Pushdown,索引条件下推)特性之前,必须先搞明白根据何登成大神总结出一套放置于所有SQL语句而皆准的where查询条 ...

  6. MySQL索引与Index Condition Pushdown(二)

    实验 先从一个简单的实验开始直观认识ICP的作用. 安装数据库 首先需要安装一个支持ICP的MariaDB或MySQL数据库.我使用的是MariaDB 5.5.34,如果是使用MySQL则需要5.6版 ...

  7. MySQL索引与Index Condition Pushdown(employees示例)

    实验 先从一个简单的实验开始直观认识ICP的作用. 安装数据库 首先需要安装一个支持ICP的MariaDB或MySQL数据库.我使用的是MariaDB 5.5.34,如果是使用MySQL则需要5.6版 ...

  8. MySQL 中Index Condition Pushdown (ICP 索引条件下推)和Multi-Range Read(MRR 索引多范围查找)查询优化

    一.ICP优化原理 Index Condition Pushdown (ICP),也称为索引条件下推,体现在执行计划的上是会出现Using index condition(Extra列,当然Extra ...

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

    ICP技术是在MySQL5.6中引入的一种索引优化技术.它能减少在使用 二级索引 过滤where条件时的回表次数 和 减少MySQL server层和引擎层的交互次数.在索引组织表中,使用二级索引进行 ...

随机推荐

  1. golang获取命令行参数

    部署golang项目时难免要通过命令行来设置一些参数,那么在golang中如何操作命令行参数呢?可以使用os库和flag库. 1.golang os库获取命令行参数 os可以通过变量Args来获取命令 ...

  2. centos7系统下安装php-fpm并配置nginx支持并开启网站gzip压缩

    注:此处不介绍nginx的安装.以下教程默认已安装nginx. 1. yum install -y php-fpm yum install php-pdo yum install php-mysql ...

  3. Scala学习笔记——断言和单元测试

    1.断言 assert(conditon)将在条件不成立的时候,抛出assertionError assert(conditon,explanation)讲在条件不成立的时候,抛出explanatio ...

  4. 【代码审计】XIAOCMS_后台database.php页面存在任意文件删除漏洞

      0x00 环境准备 XIAOCMS官网: http://www.xiaocms.com/ 网站源码版本:XiaoCms (发布时间:2014-12-29) 程序源码下载:http://www.xi ...

  5. 修改web前端访问端口

    说明: URL规则可添加变量部分,也就是说将符合同种规则的URL抽象成一个URL模式 1 2 3 @app.route('/instance/<uuid>/') def instance( ...

  6. Linux 下配置 Git 操作免登录 ssh 公钥

    cd ~/.ssh ssh-keygen -t rsa -b 4096 -C "your_email@example.com" 然后回车三连击- 可以看到当前目录下多出两个文件 i ...

  7. OpenGL——二维几何变换

    平移.旋转.缩放的实现 #include<iostream> #include <math.h> #include<Windows.h> #include < ...

  8. C# Hashtable

    哈希表(Hashtable) 在.NET Framework中,Hashtable 是 System.Collections 命名空间提供的一个容器,用于处理和表现类似 key-value 的键值对, ...

  9. -----------MSSQL生成流水号-----------------------

    --下面的代码生成长度为8的编号,编号以BH开头,其余6位为流水号.--得到新编号的函数CREATE FUNCTION f_NextBH()RETURNS char(8)ASBEGIN RETURN( ...

  10. JavaScript----特效代码

    1.不同时间段显示不同问候语 <Script Language="JavaScript"> <!-- var text=""; day = n ...