转自 http://blog.itpub.net/22664653/viewspace-1678779/

分类: MySQL

一 概念介绍
    Index Condition Pushdown (ICP)是MySQL 5.6 版本中的新特性,是一种在存储引擎层使用索引过滤数据的一种优化方式。
a 当关闭ICP时,index 仅仅是data access 的一种访问方式,存储引擎通过索引回表获取的数据会传递到MySQL Server 层进行where条件过滤。
b 当打开ICP时,如果部分where条件能使用索引中的字段,MySQL Server 会把这部分下推到引擎层,可以利用index过滤的where条件在存储引擎层进行数据过滤,而非将所有通过index access的结果传递到MySQL server层进行where过滤.
优化效果:ICP能减少引擎层访问基表的次数和MySQL Server 访问存储引擎的次数,减少io次数,提高查询语句性能。

二 原理
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.
Index Condition Pushdown is used
  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 est the remaining part of the WHERE condition that applies to this table. Accept or reject the row based on the test result.

三 实践案例
a 环境准备 
   数据库版本 5.6.16
   关闭缓存
     set query_cache_size=0;
     set query_cache_type=OFF;
   测试数据下载地址 
b 当开启ICP时

  1. mysql> SET profiling = 1;
  2. Query OK, 0 rows affected, 1 warning (0.00 sec)
  3. mysql> select * from employees where first_name='Anneke' and last_name like '%sig' ;
  4. +--------+------------+------------+-----------+--------+------------+
  5. | emp_no | birth_date | first_name | last_name | gender | hire_date |
  6. +--------+------------+------------+-----------+--------+------------+
  7. | 10006  | 1953-04-20 | Anneke     | Preusig   | F      | 1989-06-02 |
  8. +--------+------------+------------+-----------+--------+------------+
  9. 1 row in set (0.00 sec)
  10. mysql> show profiles;
  11. +----------+------------+--------------------------------------------------------------------------------+
  12. | Query_ID | Duration   | Query                                                                          |
  13. +----------+------------+--------------------------------------------------------------------------------+
  14. | 1        | 0.00060275 | select * from employees where first_name='Anneke' and last_name like '%sig'    |
  15. +----------+------------+--------------------------------------------------------------------------------+
  16. 3 rows in set, 1 warning (0.00 sec)

此时情况下根据MySQL的最左前缀原则, first_name 可以使用索引,last_name采用了like 模糊查询,不能使用索引。 
c 关闭ICP

  1. mysql> set optimizer_switch='index_condition_pushdown=off';
  2. Query OK, 0 rows affected (0.00 sec)
  3. mysql> SET profiling = 1;
  4. Query OK, 0 rows affected, 1 warning (0.00 sec)
  5. mysql> select * from employees where first_name='Anneke' and last_name like '%sig' ;
  6. +--------+------------+------------+-----------+--------+------------+
  7. | emp_no | birth_date | first_name | last_name | gender | hire_date |
  8. +--------+------------+------------+-----------+--------+------------+
  9. | 10006  | 1953-04-20 | Anneke     | Preusig   | F      | 1989-06-02 |
  10. +--------+------------+------------+-----------+--------+------------+
  11. 1 row in set (0.00 sec)
  12. mysql> SET profiling = 0;
  13. Query OK, 0 rows affected, 1 warning (0.00 sec)
  14. mysql> show profiles;
  15. +----------+------------+--------------------------------------------------------------------------------+
  16. | Query_ID | Duration   | Query                                                                          |
  17. +----------+------------+--------------------------------------------------------------------------------+
  18. | 2        | 0.00097000 | select * from employees where first_name='Anneke' and last_name like '%sig'    |
  19. +----------+------------+--------------------------------------------------------------------------------+
  20. 6 rows in set, 1 warning (0.00 sec)

当开启ICP时 查询在sending data环节时间消耗是 0.000189s

  1. mysql> show profile cpu,block io for query 1;
  2. +----------------------+----------+----------+------------+--------------+---------------+
  3. | Status               | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out |
  4. +----------------------+----------+----------+------------+--------------+---------------+
  5. | starting             | 0.000094 | 0.000000 | 0.000000   | 0            | 0             |
  6. | checking permissions | 0.000011 | 0.000000 | 0.000000   | 0            | 0             |
  7. | Opening tables       | 0.000025 | 0.000000 | 0.000000   | 0            | 0             |
  8. | init                 | 0.000044 | 0.000000 | 0.000000   | 0            | 0             |
  9. | System lock          | 0.000014 | 0.000000 | 0.000000   | 0            | 0             |
  10. | optimizing           | 0.000021 | 0.000000 | 0.000000   | 0            | 0             |
  11. | statistics           | 0.000093 | 0.000000 | 0.000000   | 0            | 0             |
  12. | preparing            | 0.000024 | 0.000000 | 0.000000   | 0            | 0             |
  13. | executing            | 0.000006 | 0.000000 | 0.000000   | 0            | 0             |
  14. | Sending data         | 0.000189 | 0.000000 | 0.000000   | 0            | 0             |
  15. | end                  | 0.000019 | 0.000000 | 0.000000   | 0            | 0             |
  16. | query end            | 0.000012 | 0.000000 | 0.000000   | 0            | 0             |
  17. | closing tables       | 0.000013 | 0.000000 | 0.000000   | 0            | 0             |
  18. | freeing items        | 0.000034 | 0.000000 | 0.000000   | 0            | 0             |
  19. | cleaning up          | 0.000007 | 0.000000 | 0.000000   | 0            | 0             |
  20. +----------------------+----------+----------+------------+--------------+---------------+
  21. 15 rows in set, 1 warning (0.00 sec)

当关闭ICP时 查询在sending data环节时间消耗是 0.000735s

  1. mysql> show profile cpu,block io for query 2;
  2. +----------------------+----------+----------+------------+--------------+---------------+
  3. | Status               | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out |
  4. +----------------------+----------+----------+------------+--------------+---------------+
  5. | starting             | 0.000045 | 0.000000 | 0.000000   | 0            | 0             |
  6. | checking permissions | 0.000007 | 0.000000 | 0.000000   | 0            | 0             |
  7. | Opening tables       | 0.000015 | 0.000000 | 0.000000   | 0            | 0             |
  8. | init                 | 0.000024 | 0.000000 | 0.000000   | 0            | 0             |
  9. | System lock          | 0.000009 | 0.000000 | 0.000000   | 0            | 0             |
  10. | optimizing           | 0.000012 | 0.000000 | 0.000000   | 0            | 0             |
  11. | statistics           | 0.000049 | 0.000000 | 0.000000   | 0            | 0             |
  12. | preparing            | 0.000016 | 0.000000 | 0.000000   | 0            | 0             |
  13. | executing            | 0.000005 | 0.000000 | 0.000000   | 0            | 0             |
  14. | Sending data         | 0.000735 | 0.001000 | 0.000000   | 0            | 0             |
  15. | end                  | 0.000008 | 0.000000 | 0.000000   | 0            | 0             |
  16. | query end            | 0.000008 | 0.000000 | 0.000000   | 0            | 0             |
  17. | closing tables       | 0.000009 | 0.000000 | 0.000000   | 0            | 0             |
  18. | freeing items        | 0.000023 | 0.000000 | 0.000000   | 0            | 0             |
  19. | cleaning up          | 0.000007 | 0.000000 | 0.000000   | 0            | 0             |
  20. +----------------------+----------+----------+------------+--------------+---------------+
  21. 15 rows in set, 1 warning (0.00 sec)

从上面的profile 可以看出ICP 开启时整个sql 执行时间是未开启的2/3,sending data 环节的时间消耗前者仅是后者的1/4。

ICP 开启时的执行计划 含有 Using index condition 标示 ,表示优化器使用了ICP对数据访问进行优化。

  1. mysql> explain select * from employees where first_name='Anneke' and last_name like '%nta' ;
  2. +----+-------------+-----------+------+---------------+--------------+---------+-------+------+-----------------------+
  3. | id | select_type | table     | type | possible_keys | key          | key_len | ref   | rows | Extra                 |
  4. +----+-------------+-----------+------+---------------+--------------+---------+-------+------+-----------------------+
  5. | 1  | SIMPLE      | employees | ref  | idx_emp_fnln  | idx_emp_fnln | 44      | const | 224  | Using index condition |
  6. +----+-------------+-----------+------+---------------+--------------+---------+-------+------+-----------------------+
  7. 1 row in set (0.00 sec)

ICP 关闭时的执行计划显示use where.

  1. mysql> explain select * from employees where first_name='Anneke' and last_name like '%nta' ;
  2. +----+-------------+-----------+------+---------------+--------------+---------+-------+------+-------------+
  3. | id | select_type | table     | type | possible_keys | key          | key_len | ref   | rows | Extra       |
  4. +----+-------------+-----------+------+---------------+--------------+---------+-------+------+-------------+
  5. | 1  | SIMPLE      | employees | ref  | idx_emp_fnln  | idx_emp_fnln | 44      | const | 224  | Using where |
  6. +----+-------------+-----------+------+---------------+--------------+---------+-------+------+-------------+
  7. 1 row in set (0.00 sec)

案例分析
以上面的查询为例关闭ICP 时,存储引擎通前缀index first_name 访问表中225条first_name 为Anneke的数据,并在MySQL server层根据last_name like '%sig' 进行过滤
开启ICP 时,last_name 的like '%sig'条件可以通过索引字段last_name 进行过滤,在存储引擎内部通过与where条件的对比,直接过滤掉不符合条件的数据。该过程不回表,只访问符合条件的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 5.6 版本的不支持分表的ICP 功能,5.7 版本的开始支持。
7 当sql 使用覆盖索引时,不支持ICP 优化方法。

  1. mysql> explain select * from employees where first_name='Anneke' and last_name='Porenta' ;
  2. +----+-------------+-----------+------+---------------+--------------+---------+-------------+------+-----------------------+
  3. | id | select_type | table     | type | possible_keys | key          | key_len | ref         | rows | Extra                 |
  4. +----+-------------+-----------+------+---------------+--------------+---------+-------------+------+-----------------------+
  5. | 1  | SIMPLE | employees      | ref  | idx_emp_fnln  | idx_emp_fnln | 94      | const,const | 1    | Using index condition |
  6. +----+-------------+-----------+------+---------------+--------------+---------+-------------+------+-----------------------+
  7. 1 row in set (0.00 sec)
  8. mysql> explain select first_name,last_name from employees where first_name='Anneke' and last_name='Porenta' ;
  9. +----+-------------+-----------+------+---------------+--------------+---------+-------------+------+--------------------------+
  10. | id | select_type | table     | type | possible_keys | key          | key_len | ref         | rows | Extra                    |
  11. +----+-------------+-----------+------+---------------+--------------+---------+-------------+------+--------------------------+
  12. | 1  | SIMPLE      | employees | ref  | idx_emp_fnln  | idx_emp_fnln | 94      | const,const | 1    | Using where; Using index |
  13. +----+-------------+-----------+------+---------------+--------------+---------+-------------+------+--------------------------+
  14. 1 row in set (0.00 sec)

0926MySQL中ICP索引下推的更多相关文章

  1. MySQL5.6之Index Condition Pushdown(ICP,索引条件下推)-Using index condition

    http://blog.itpub.net/22664653/viewspace-1210844/ -- 这篇博客写的更细,以后看 ICP(index condition pushdown)是mysq ...

  2. 神奇的 SQL 之 ICP → 索引条件下推

    开心一刻 楼主:来,我们先排练一遍 小伙伴们:好 嘿.哈.嚯 楼主:非常好,就是这个节奏,我们开始吧 楼主:啊.啊.啊,疼 ! 你们是不是故意的 ? 回表与覆盖索引 正式讲 ICP 之前了,我们先将相 ...

  3. Mysql系列(十二)—— 索引下推优化

    索引条件下推(ICP)是对MySQL使用索引从表中检索行的情况的优化.如果没有ICP,存储引擎会遍历索引以查找基表中的行,并将它们返回给MySQL服务器,该服务器会评估WHERE行的条件.启用ICP后 ...

  4. MySQL索引解析(联合索引/最左前缀/覆盖索引/索引下推)

    本节内容: 1)索引基础 2)索引类型(Hash索引.有序数组.B+树) 3)索引的几个常见问题 1)联合索引 2)最左前缀原则 3)覆盖索引 4)索引下推 1. 索引基础 索引对查询的速度有着至关重 ...

  5. 五分钟搞懂MySQL索引下推

    大家好,我是老三,今天分享一个小知识点--索引下推. 如果你在面试中,听到MySQL5.6"."索引优化" 之类的词语,你就要立马get到,这个问的是"索引下推 ...

  6. InnoDB 聚集索引和非聚集索引、覆盖索引、回表、索引下推简述

    关于InnoDB 存储引擎的有聚集索引和非聚集索引,覆盖索引,回表,索引下推等概念,这些知识点比较多,也比较零碎,但是概念都是基于索引建立的,本文从索引查找数据讲述上述概念. 聚集索引和非聚集索引 在 ...

  7. MySQL索引下推,原来这么简单!

    大家好,我是大彬~ 今天给大家分享MySQL的索引下推. 什么是索引下推 索引条件下推,也叫索引下推,英文全称Index Condition Pushdown,简称ICP. 索引下推是MySQL5.6 ...

  8. MySQL查询性能优化七种武器之索引下推

    前面已经讲了MySQL的其他查询性能优化方式,没看过可以去了解一下: MySQL查询性能优化七种武器之索引潜水 MySQL查询性能优化七种武器之链路追踪 今天要讲的是MySQL的另一种查询性能优化方式 ...

  9. MySQL索引下推技术

    索引下推整个思路如下: To see how this optimization works, consider first how an index scan proceeds when Index ...

随机推荐

  1. 前缀和&&离散化

    现在正在上课,但我还是要同步更新博文...\滑稽 先讲一个离散化,就是把几个离的特别远的数在不影响结果的情况下,变成相近的数.倒是没什么影响,但应用在数组下标的话可以节约空间.(貌似和hash有点像) ...

  2. Java中的锁概念

    掌握Java中锁是Java多线程编程中绕不开的知识,只有知道理解Java各种锁才能在编码过程中灵活运用,写出更高效的多线程程序.而理解掌握锁的第一步,可从宏观上对比理解一下各种锁概念. 公平锁/非公平 ...

  3. OC常用的数学函数及宏定义

    一.函数 1. 三角函数 double sin (double);正弦 double cos (double);余弦 double tan (double);正切 2 .反三角函数 double as ...

  4. 前端面试准备之JavaScript

    1.数据类型. JavaScript中有5种简单数据类型(也称为基本数据类型):Undefined.Null.Boolean.Number和String.还有1种复杂数据类型——Object,Obje ...

  5. PCB MongoDB数据库 备份与还原

    一. MongoDB数据库 备份与还原工具介绍: 数据备份工具  mongodump.exe 数据还原工具   mongorestore.exe 二. MongoDB数据库备份 mongodump - ...

  6. Gold Balanced Lineup(hash)

    http://poj.org/problem?id=3274 ***** #include <stdio.h> #include <iostream> #include < ...

  7. lodop多打印一页白纸

    [错误还原]Lodop多张空白页测试2 [错误还原]Lodop多出空白页测试 http://blog.sina.com.cn/s/blog_157ebf1370102wta1.html 上面这个链接是 ...

  8. Docker EE/Docker CE简介与版本规划

    随着Docker的不断流行与发展,docker公司(或称为组织)也开启了商业化之路,Docker 从 17.03版本之后分为 CE(Community Edition) 和 EE(Enterprise ...

  9. oracle 创建命令

    环境变量设置(在Sqlplus中执行) create or replace directory filepath as 'D:\ORACLEBACKUP'; 备份脚本:expdp system/123 ...

  10. 进击的Python【第二十二章】

    day22 知识点概要 - Session - CSRF - Model操作 - Form验证(ModelForm) - 中间件 - 缓存 - 信号 内容详细: 1. Session 基于Cookie ...