MySQL ICP(Index Condition Pushdown)特性
一、SQL的where条件提取规则
在ICP(Index Condition Pushdown,索引条件下推)特性之前,必须先搞明白根据何登成大神总结出一套放置于所有SQL语句而皆准的where查询条件的提取规则:所有SQL的where条件,均可归纳为3大类:Index Key (First Key & Last Key),Index Filter,Table Filter。
接下来,简单说一下这3大类分别是如何定义,以及如何提取的,详情请看:SQL语句中where条件在数据库中提取与应用浅析。
Index Key(Fist key & Last Key),Index Filter,Table Filter
Index First Key
只是用来定位索引的起始范围,因此只在索引第一次Search Path(沿着索引B+树的根节点一直遍历,到索引正确的叶节点位置)时使用,一次判断即可;
Index Last Key
用来定位索引的终止范围,因此对于起始范围之后读到的每一条索引记录,均需要判断是否已经超过了Index Last Key的范围,若超过,则当前查询结束;
Index Filter
用于过滤索引查询范围中不满足查询条件的记录,因此对于索引范围中的每一条记录,均需要与Index Filter进行对比,若不满足Index Filter则直接丢弃,继续读取索引下一条记录;
Table Filter
则是最后一道where条件的防线,用于过滤通过前面索引的层层考验的记录,此时的记录已经满足了Index First Key与Index Last Key构成的范围,并且满足Index Filter的条件,回表读取了完整的记录,判断完整记录是否满足Table Filter中的查询条件,同样的,若不满足,跳过当前记录,继续读取索引的下一条记录,若满足,则返回记录,此记录满足了where的所有条件,可以返回给前端用户。
二、ICP特性介绍
Index Condition Pushdown (ICP)是MySQL 5.6版本中的新特性,是一种在存储引擎层使用索引过滤数据的一种优化方式。
我对Using index condition的理解是,首先mysql server和storage engine是两个组件,server负责sql的parse,执行; storage engine去真正的做数据/index的读取/写入。以前是这样:server命令storage engine按index key把相应的数据从数据表读出,传给server,然后server来按where条件(index filter和table filter)做选择。
而在MySQL 5.6加入ICP后,Index Filter与Table Filter分离,Index Filter下降到InnoDB的索引层面进行过滤,如果不符合条件则无须读数据表,减少了回表与返回MySQL Server层的记录交互开销,节省了disk IO,提高了SQL的执行效率。
原理
a. 当关闭ICP时,index仅仅是data access的一种访问方式,存储引擎通过索引回表获取的数据会传递到MySQL Server层进行where条件过滤,也就是做index filter和table filter。
b. 当打开ICP时,如果部分where条件能使用索引中的字段,MySQL Server会把这部分下推到引擎层,可以利用index filter的where条件在存储引擎层进行数据过滤,而非将所有通过index access的结果传递到MySQL server层进行where过滤。
优化效果:ICP能减少引擎层访问基表的次数和MySQL Server访问存储引擎的次数,减少io次数,提高查询语句性能。
三、测试ICP优化SQL
本文选用MySQL官方文档中提供的示例数据库之一:employees。这个数据库关系复杂度适中,且数据量较大。下图是这个数据库的E-R关系图(引用自MySQL官方手册):
MySQL官方文档中关于此数据库的页面为:https://dev.mysql.com/doc/employee/en,里面详细介绍了此数据库,并提供了下载地址和导入方法,如果有兴趣导入此数据库到自己的MySQL可以参考文中内容。
可以选择下载测试数据:https://github.com/datacharmer/test_db
关闭缓存(最好关闭后重启MySQL)
mysql> set global query_cache_size=0;
mysql> set global query_cache_type=OFF;
导入employees库,需要自己手动创建一个联合索引。
mysql> alter table employees add index first_last(first_name,last_name);
其表结构如下:
mysql> show create table employees\G
*************************** 1. row ***************************
Table: employees
Create Table: CREATE TABLE `employees` (
`emp_no` int(11) NOT NULL,
`birth_date` date NOT NULL,
`first_name` varchar(14) NOT NULL,
`last_name` varchar(16) NOT NULL,
`gender` enum('M','F') NOT NULL,
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`),
KEY `first_last` (`first_name`,`last_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)
当开启ICP时(默认开启)
mysql> SET profiling = 1;
Query OK, 0 rows affected, 1 warning (0.00 sec) mysql> select SQL_NO_CACHE * from employees where first_name='Anneke' and last_name like '%Preusig' ;
+--------+------------+------------+-----------+--------+------------+
| emp_no | birth_date | first_name | last_name | gender | hire_date |
+--------+------------+------------+-----------+--------+------------+
| 10006 | 1953-04-20 | Anneke | Preusig | F | 1989-06-02 |
+--------+------------+------------+-----------+--------+------------+
1 row in set (0.00 sec)
此时情况下根据MySQL的最左前缀原则,irst_name 可以使用索引,last_name采用了like 模糊查询,不能使用索引。
当关闭ICP时
mysql> set optimizer_switch='index_condition_pushdown=off';
Query OK, 0 rows affected (0.00 sec) mysql> select SQL_NO_CACHE * from employees where first_name='Anneke' and last_name like '%Preusig' ;
+--------+------------+------------+-----------+--------+------------+
| emp_no | birth_date | first_name | last_name | gender | hire_date |
+--------+------------+------------+-----------+--------+------------+
| 10006 | 1953-04-20 | Anneke | Preusig | F | 1989-06-02 |
+--------+------------+------------+-----------+--------+------------+
1 row in set (0.00 sec) mysql> SET profiling = 0;
Query OK, 0 rows affected, 1 warning (0.00 sec) mysql> show profiles;
+----------+------------+---------------------------------------------------------------------------------+
| Query_ID | Duration | Query |
+----------+------------+---------------------------------------------------------------------------------+
| 1 | 0.00108900 | select * from employees where first_name='Anneke' and last_name like '%Preusig' |
| 2 | 0.00025375 | set optimizer_switch='index_condition_pushdown=off' |
| 3 | 0.00231650 | select * from employees where first_name='Anneke' and last_name like '%Preusig' |
+----------+------------+---------------------------------------------------------------------------------+
5 rows in set, 1 warning (0.00 sec)
当开启ICP时,查询在sending data环节时间消耗是 0.00108900s
当关闭ICP时,查询在sending data环节时间消耗是 0.00231650s
从上面的profile可以看出ICP开启时整个sql 执行时间是未开启的2/3,sending data 环节的时间消耗前者仅是后者的1/4。
mysql> set optimizer_switch='index_condition_pushdown=on';
Query OK, 0 rows affected (0.00 sec) mysql> explain select * from employees where first_name='Anneke' and last_name like '%nta' ;
+----+-------------+-----------+------+---------------+------------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+------+---------------+------------+---------+-------+------+-----------------------+
| 1 | SIMPLE | employees | ref | first_last | first_last | 58 | const | 224 | Using index condition |
+----+-------------+-----------+------+---------------+------------+---------+-------+------+-----------------------+
1 row in set (0.00 sec) mysql> explain select * from employees where first_name='Anneke' ;
+----+-------------+-----------+------+---------------+------------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+------+---------------+------------+---------+-------+------+-----------------------+
| 1 | SIMPLE | employees | ref | first_last | first_last | 58 | const | 224 | Using index condition |
+----+-------------+-----------+------+---------------+------------+---------+-------+------+-----------------------+
1 row in set (0.00 sec) mysql> set optimizer_switch='index_condition_pushdown=off';
Query OK, 0 rows affected (0.00 sec) mysql> explain select * from employees where first_name='Anneke' and last_name like '%nta' ;
+----+-------------+-----------+------+---------------+------------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+------+---------------+------------+---------+-------+------+-------------+
| 1 | SIMPLE | employees | ref | first_last | first_last | 58 | const | 224 | Using where |
+----+-------------+-----------+------+---------------+------------+---------+-------+------+-------------+
1 row in set (0.00 sec)
四、案例分析
以上面的查询为例,关闭ICP时,存储引擎通前缀index first_name(视为index key)访问表中数据,并在MySQL server层根据where条件last_name like ‘%nta’(视为index filter)进行过滤。
开启ICP时,MySQL server把index filter(last_name like ‘%nta’)推到存储引擎层,在存储引擎内部通过与where条件last_name like ‘%nta’的对比,直接过滤掉不符合条件的数据,然后返回最终数据给MySQL server层。该过程减少了回表操作,只访问符合条件的1条记录并返回给MySQL Server ,有效的减少了io访问和各层之间的交互。
ICP关闭时 ,仅仅使用索引作为访问数据的方式。
ICP 开启时 ,MySQL将在存储引擎层 利用索引过滤数据,减少不必要的回表。
注意虚线的using where表示如果where条件中含有没有被索引的字段,则还是要经过MySQL Server 层过滤。
五、ICP的使用限制
1. 当sql需要全表访问时,ICP的优化策略可用于range, ref, eq_ref, ref_or_null类型的访问数据方法 。
2. 支持InnoDB和MyISAM表。
3. ICP只能用于二级索引,不能用于主索引。
4. 并非全部where条件都可以用ICP筛选,如果where条件的字段不在索引列中,还是要读取整表的记录到server端做where过滤。
5. ICP的加速效果取决于在存储引擎内通过ICP筛选掉的数据的比例。
6. MySQL 5.6版本的不支持分表的ICP功能,5.7版本的开始支持。
7. 当sql使用覆盖索引时,不支持ICP优化方法。
原文链接:http://blog.itpub.net/22664653/viewspace-1210844/
MySQL ICP(Index Condition Pushdown)特性的更多相关文章
- MySQL 中Index Condition Pushdown (ICP 索引条件下推)和Multi-Range Read(MRR 索引多范围查找)查询优化
一.ICP优化原理 Index Condition Pushdown (ICP),也称为索引条件下推,体现在执行计划的上是会出现Using index condition(Extra列,当然Extra ...
- MySQL 之 Index Condition Pushdown(ICP)
简介 Index Condition Pushdown (ICP)是MySQL 5.6 版本中的新特性,是一种在存储引擎层使用索引过滤数据的一种优化方式. 当关闭ICP时,index 仅仅是data ...
- MySQL 优化之 ICP (index condition pushdown:索引条件下推)
ICP技术是在MySQL5.6中引入的一种索引优化技术.它能减少在使用 二级索引 过滤where条件时的回表次数 和 减少MySQL server层和引擎层的交互次数.在索引组织表中,使用二级索引进行 ...
- 【mysql】关于Index Condition Pushdown特性
ICP简介 Index Condition Pushdown (ICP) is an optimization for the case where MySQL retrieves rows from ...
- MySQL中Index Condition Pushdown(ICP)优化
在MySQL 5.6开始支持的一种根据索引进行查询的优化方式.之前的MySQL数据库版本不支持ICP,当进行索引查询是,首先根据索引来查找记录,然后在根据WHERE条件来过滤记录.在支持ICP后,My ...
- mysql -- 优化之ICP(index condition pushdown)
一.为了方法说明ICP是什么.假设有如下的表和查询: create table person( id int unsigned auto_increment primary key, home_add ...
- 浅析MySQL中的Index Condition Pushdown (ICP 索引条件下推)和Multi-Range Read(MRR 索引多范围查找)查询优化
本文出处:http://www.cnblogs.com/wy123/p/7374078.html(保留出处并非什么原创作品权利,本人拙作还远远达不到,仅仅是为了链接到原文,因为后续对可能存在的一些错误 ...
- MySQL 5.6新特性 -- Index Condition Pushdown
Index Condition Pushdown(ICP)是针对mysql使用索引从表中检索行数据时的一种优化方法. 在没有ICP特性之前,存储引擎根据索引去基表查找并将数据返回给mysql se ...
- 1229【MySQL】性能优化之 Index Condition Pushdown
转自http://blog.itpub.net/22664653/viewspace-1210844/ [MySQL]性能优化之 Index Condition Pushdown2014-07-06 ...
随机推荐
- python网络编程及高并发问题
面试其他篇 目录: 1.1
- Android之单元测试及数据库操作
一.安卓下的单元测试1.创建一个单元类,继承超类AndroidTestCase2.在AndroidManifest.xml配置清单中配置以下两点首先在manifest节点下添加节点instrument ...
- Stanford CS231n实践笔记(课时14卷积神经网络详解 上)
本课我们主要来研究一个"浏览器中的卷积神经网络" 这只是一个展示项目,但是能够帮助直观地看到一些东西 地址:https://cs.stanford.edu/people/karpa ...
- 牛客网数据库SQL实战(6-10)
6.查找所有员工入职时候的薪水情况,给出emp_no以及salary, 并按照emp_no进行逆序CREATE TABLE `employees` (`emp_no` int(11) NOT NULL ...
- Python3基础 list in/not in 判断一个变量是否在列表中存在
Python : 3.7.0 OS : Ubuntu 18.04.1 LTS IDE : PyCharm 2018.2.4 Conda ...
- Ubuntu 汉字显示一半的修复
部分汉字(例如“复”)显示不正常,只显示一半,其原因是Ubuntu采用的字体Noto Sans CJK优先显示日文汉字,这一问题可以通过修改配置文件/etc/fonts/conf.avail/64-l ...
- CF1131D tarjan,拓扑
题目链接 541div2 http://codeforces.com/contest/1131/problem/D 思路 给出n序列和m序列的相对大小关系 构造出最大值最小的序列 缩点+拓扑 小的向大 ...
- Linux配置ssh服务和XShell连接Linux
SSH服务查看和安装,配置: https://www.cnblogs.com/qiuqiuqiu/p/6445426.html https://www.cnblogs.com/yunweis/p/77 ...
- 【字符串区别】SQLServer中char、varchar、nchar、nvarchar的区别:
一.定义 char: 固定长度,存储ANSI字符,不足的补英文半角空格. nchar: 固定长度,存储Unicode字符,不足的补英文半角空格 varchar: 可变长度,存储ANSI字符 ...
- 网络_TCP连接的建立与释放
三报文握手 1.概述 TCP是面向连接的协议.TCP建立连接的过程叫做握手,握手需要在客户和服务器之间交换三个TCP报文段,即我们说的"三次握手"(严格讲是一次握手过程中交换了三个 ...