【MySQL】MySQL5.6新特性之Index Condition Pushdown

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
云数据库 RDS MySQL,高可用系列 2核4GB
简介:
一 概念介绍
     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.

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

b 当开启ICP时


mysql> SET profiling = 1;

Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> select * from employees where first_name='Anneke' and last_name like '%sig' ;

+--------+------------+------------+-----------+--------+------------+

| 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> show profiles;

+----------+------------+--------------------------------------------------------------------------------+

| Query_ID | Duration   | Query                                                                          |

+----------+------------+--------------------------------------------------------------------------------+

| 1        | 0.00060275 | select * from employees where first_name='Anneke' and last_name like '%sig'    |

+----------+------------+--------------------------------------------------------------------------------+

3 rows in set, 1 warning (0.00 sec) 

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


mysql> set optimizer_switch='index_condition_pushdown=off';

Query OK, 0 rows affected (0.00 sec)

mysql> SET profiling = 1;

Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> select * from employees where first_name='Anneke' and last_name like '%sig' ;

+--------+------------+------------+-----------+--------+------------+

| 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                                                                          |

+----------+------------+--------------------------------------------------------------------------------+

| 2        | 0.00097000 | select * from employees where first_name='Anneke' and last_name like '%sig'    |

+----------+------------+--------------------------------------------------------------------------------+

6 rows in set, 1 warning (0.00 sec) 

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


mysql> show profile cpu,block io for query 1;

+----------------------+----------+----------+------------+--------------+---------------+

| Status               | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out |

+----------------------+----------+----------+------------+--------------+---------------+

| starting             | 0.000094 | 0.000000 | 0.000000   | 0            | 0             |

| checking permissions | 0.000011 | 0.000000 | 0.000000   | 0            | 0             |

| Opening tables       | 0.000025 | 0.000000 | 0.000000   | 0            | 0             |

| init                 | 0.000044 | 0.000000 | 0.000000   | 0            | 0             |

| System lock          | 0.000014 | 0.000000 | 0.000000   | 0            | 0             |

| optimizing           | 0.000021 | 0.000000 | 0.000000   | 0            | 0             |

| statistics           | 0.000093 | 0.000000 | 0.000000   | 0            | 0             |

| preparing            | 0.000024 | 0.000000 | 0.000000   | 0            | 0             |

| executing            | 0.000006 | 0.000000 | 0.000000   | 0            | 0             |

| Sending data         | 0.000189 | 0.000000 | 0.000000   | 0            | 0             |

| end                  | 0.000019 | 0.000000 | 0.000000   | 0            | 0             |

| query end            | 0.000012 | 0.000000 | 0.000000   | 0            | 0             |

| closing tables       | 0.000013 | 0.000000 | 0.000000   | 0            | 0             |

| freeing items        | 0.000034 | 0.000000 | 0.000000   | 0            | 0             |

| cleaning up          | 0.000007 | 0.000000 | 0.000000   | 0            | 0             |

+----------------------+----------+----------+------------+--------------+---------------+

15 rows in set, 1 warning (0.00 sec) 

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


mysql> show profile cpu,block io for query 2;

+----------------------+----------+----------+------------+--------------+---------------+

| Status               | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out |

+----------------------+----------+----------+------------+--------------+---------------+

| starting             | 0.000045 | 0.000000 | 0.000000   | 0            | 0             |

| checking permissions | 0.000007 | 0.000000 | 0.000000   | 0            | 0             |

| Opening tables       | 0.000015 | 0.000000 | 0.000000   | 0            | 0             |

| init                 | 0.000024 | 0.000000 | 0.000000   | 0            | 0             |

| System lock          | 0.000009 | 0.000000 | 0.000000   | 0            | 0             |

| optimizing           | 0.000012 | 0.000000 | 0.000000   | 0            | 0             |

| statistics           | 0.000049 | 0.000000 | 0.000000   | 0            | 0             |

| preparing            | 0.000016 | 0.000000 | 0.000000   | 0            | 0             |

| executing            | 0.000005 | 0.000000 | 0.000000   | 0            | 0             |

| Sending data         | 0.000735 | 0.001000 | 0.000000   | 0            | 0             |

| end                  | 0.000008 | 0.000000 | 0.000000   | 0            | 0             |

| query end            | 0.000008 | 0.000000 | 0.000000   | 0            | 0             |

| closing tables       | 0.000009 | 0.000000 | 0.000000   | 0            | 0             |

| freeing items        | 0.000023 | 0.000000 | 0.000000   | 0            | 0             |

| cleaning up          | 0.000007 | 0.000000 | 0.000000   | 0            | 0             |

+----------------------+----------+----------+------------+--------------+---------------+

15 rows in set, 1 warning (0.00 sec) 

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

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


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  | idx_emp_fnln  | idx_emp_fnln | 44      | const | 224  | Using index condition |

+----+-------------+-----------+------+---------------+--------------+---------+-------+------+-----------------------+

1 row in set (0.00 sec) 

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

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  | idx_emp_fnln  | idx_emp_fnln | 44      | const | 224  | Using where |

+----+-------------+-----------+------+---------------+--------------+---------+-------+------+-------------+

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 优化方法。


mysql> explain select * from employees where first_name='Anneke' and last_name='Porenta' ;

+----+-------------+-----------+------+---------------+--------------+---------+-------------+------+-----------------------+

| id | select_type | table     | type | possible_keys | key          | key_len | ref         | rows | Extra                 |

+----+-------------+-----------+------+---------------+--------------+---------+-------------+------+-----------------------+

| 1  | SIMPLE | employees      | ref  | idx_emp_fnln  | idx_emp_fnln | 94      | const,const | 1    | Using index condition |

+----+-------------+-----------+------+---------------+--------------+---------+-------------+------+-----------------------+

1 row in set (0.00 sec)

mysql> explain select first_name,last_name from employees where first_name='Anneke' and last_name='Porenta' ;

+----+-------------+-----------+------+---------------+--------------+---------+-------------+------+--------------------------+

| id | select_type | table     | type | possible_keys | key          | key_len | ref         | rows | Extra                    |

+----+-------------+-----------+------+---------------+--------------+---------+-------------+------+--------------------------+

| 1  | SIMPLE      | employees | ref  | idx_emp_fnln  | idx_emp_fnln | 94      | const,const | 1    | Using where; Using index |

+----+-------------+-----------+------+---------------+--------------+---------+-------------+------+--------------------------+

1 row in set (0.00 sec) 

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
相关文章
|
9月前
|
SQL 安全 关系型数据库
【MySQL基础篇】事务(事务操作、事务四大特性、并发事务问题、事务隔离级别)
事务是MySQL中一组不可分割的操作集合,确保所有操作要么全部成功,要么全部失败。本文利用SQL演示并总结了事务操作、事务四大特性、并发事务问题、事务隔离级别。
4074 56
【MySQL基础篇】事务(事务操作、事务四大特性、并发事务问题、事务隔离级别)
|
8月前
|
存储 关系型数据库 MySQL
MySQL中为什么要使用索引合并(Index Merge)?
通过这些内容的详细介绍和实际案例分析,希望能帮助您深入理解索引合并及其在MySQL中的
452 10
|
10月前
|
关系型数据库 MySQL
mysql事务特性
原子性:一个事务内的操作统一成功或失败 一致性:事务前后的数据总量不变 隔离性:事务与事务之间相互不影响 持久性:事务一旦提交发生的改变不可逆
|
12月前
|
JSON 关系型数据库 MySQL
MySQL 8.0 新特性
MySQL 8.0 新特性
346 10
MySQL 8.0 新特性
|
10月前
|
存储 关系型数据库 MySQL
MySQL 8.0特性-自增变量的持久化
【11月更文挑战第8天】在 MySQL 8.0 之前,自增变量(`AUTO_INCREMENT`)的行为在服务器重启后可能会发生变化,导致意外结果。MySQL 8.0 引入了自增变量的持久化特性,将其信息存储在数据字典中,确保重启后的一致性。这提高了开发和管理的稳定性,减少了主键冲突和数据不一致的风险。默认情况下,MySQL 8.0 启用了这一特性,但在升级时需注意行为变化。
207 1
|
11月前
|
SQL 安全 关系型数据库
MySQL8.2有哪些新特性?
【10月更文挑战第3天】MySQL8.2有哪些新特性?
296 2
|
3月前
|
分布式计算 运维 监控
Fusion 引擎赋能:流利说如何用阿里云 Serverless Spark 实现数仓计算加速
本文介绍了流利说与阿里云合作,利用EMR Serverless Spark优化数据处理的全过程。流利说是科技驱动的教育公司,通过AI技术提升用户英语水平。原有架构存在资源管理、成本和性能等痛点,采用EMR Serverless Spark后,实现弹性资源管理、按需计费及性能优化。方案涵盖数据采集、存储、计算到查询的完整能力,支持多种接入方式与高效调度。迁移后任务耗时减少40%,失败率降低80%,成本下降30%。未来将深化合作,探索更多行业解决方案。
152 1
|
4月前
|
SQL 关系型数据库 MySQL
客户说|保险极客引入阿里云AnalyticDB,多业务场景效率大幅提升
“通过引入AnalyticDB,我们在复杂数据查询和实时同步方面取得了显著突破,其分布式、弹性与云计算的优势得以充分体现,帮助企业快速响应业务变化,实现降本增效。AnalyticDB的卓越表现保障了保险极客数据服务的品质和效率。”
|
7月前
|
存储 分布式计算 物联网
美的楼宇科技基于阿里云 EMR Serverless Spark 构建 LakeHouse 湖仓数据平台
美的楼宇科技基于阿里云 EMR Serverless Spark 建设 IoT 数据平台,实现了数据与 AI 技术的有效融合,解决了美的楼宇科技设备数据量庞大且持续增长、数据半结构化、数据价值缺乏深度挖掘的痛点问题。并结合 EMR Serverless StarRocks 搭建了 Lakehouse 平台,最终实现不同场景下整体性能提升50%以上,同时综合成本下降30%。
555 58

推荐镜像

更多