MySQL--索引条件下推优化

  http://blog.163.com/li_hx/blog/static/1839914132015782821512/

 
 

一 什么是“索引条件下推”mysql

 
 

“索引条件下推”,称为 Index Condition Pushdown (ICP),这是MySQL提供的用某一个索引对一个特定的表从表中获取元组”,注意咱们这里特地强调了“一个”,这是由于这样的索引优化不是用于多表链接而是用于单表扫描,确切地说,是单表利用索引进行扫描以获取数据的一种方式。 sql

 
 

 

 
 

“索引条件下推”的目的数据库

 
 

用ySQL官方手册描述:函数

 
 

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

 
 

这句官方描述,一是说明减小完整记录(一条完整元组)读取的个数;二是说明对于InnoDB汇集索引无效,只能是对SECOND INDEX这样的非汇集索引有效。优化

 
 

 

 
 

三 原理ui

 
 

先看实例:this

 
 

 

mysql> set optimizer_switch='index_condition_pushdown=off'; //关闭ICP
Query OK, 0 rows affected (0.00 sec)
mysql> EXPLAIN SELECT * FROM t4 WHERE 1=t4.a4 AND t4.name like 'char%';
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type  | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | t4    | NULL       | range | a4_i          | a4_i | 28      | NULL |    1 |   100.00 | Using where |
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
mysql> set optimizer_switch='index_condition_pushdown=on';  //打开ICP,则Extra列中显示“Using index condition
Query OK, 0 rows affected (0.00 sec)
mysql> EXPLAIN SELECT * FROM t4 WHERE 1=t4.a4 AND t4.name like 'char%';
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+-----------------------+
| id | select_type | table | partitions | type  | possible_keys | key  | key_len | ref  | rows | filtered | Extra                 |
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+-----------------------+
|  1 | SIMPLE      | t4    | NULL       | range | a4_i          | a4_i | 28      | NULL |    1 |   100.00 | Using index condition |
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)
若是打开ICP,则执行计划的Extra列会显示“Using index condition”,这代表在。
 
借用网上的2张图加以改造,并配以解释,来讲明原理,更清晰地说明问题。
 
图一:不使用ICP技术(过程使用数字符号标示,如①②③等)
 

 


过程解释:
①:MySQL Server发出读取数据的命令,这是在执行器中执行以下代码段,经过函数指针和handle接口调用存储引擎的索引读或全表表读。此处进行的是索引读。
    if (in_first_read)
    {
      in_first_read= false;
      error= (*qep_tab->read_first_record)(qep_tab); //设定合适的读取函数,如设定索引读函数/全表扫描函数
    }
    else
      error= info->read_record(info);
②、③:进入存储引擎,读取索引树,在索引树上查找,把知足条件的(通过查找,红色的知足)从表记录中读出(步骤④,一般有IO),从存储引擎返回⑤标识的结果。此处,不只要在索引行进行索引读取(一般是内存中,速度快。步骤③),还要进行进行步骤④,一般有IO。
⑥:从存储引擎返回查找到的多条元组给MySQL Server,MySQL Server在⑦获得较多的元组。
⑦--⑧:⑦到⑧依据WHERE子句条件进行过滤,获得知足条件的元组。注意在MySQL Server层获得较多元组,而后才过滤,最终获得的是少许的、符合条件的元组。
 
图二:使用ICP技术(过程使用数字符号标示,如①②③等)
 
 

 

 
 
 
过程解释:
①:MySQL Server发出读取数据的命令,过程同图一。
②、③:进入存储引擎,读取索引树,在索引树上查找,把知足已经下推的条件的(通过查找,红色的知足)从表记录中读出(步骤④,一般有IO),从存储引擎返回⑤标识的结果。此处,不只要在索引行进行索引读取(一般是内存中,速度快。步骤③),还要在③这个阶段依据下推的条件进行进行判断,不知足条件的,不去读取表中的数据,直接在索引树上进行下一个索引项的判断,直到有知足条件的,才进行步骤④,这样,较没有ICP的方式,IO量减小。
⑥:从存储引擎返回查找到的少许元组给MySQL Server,MySQL Server在⑦获得少许的元组。所以比较图一无ICP的方式,返回给MySQL Server层的便是少许的、符合条件的元组。
 另外,图中的部件层次关系,再也不进行解释。
四 实现细节
1 ICP只能用于辅助索引,不能用于汇集索引。
2 ICP只用于单表,不是多表链接是的链接条件部分(如开篇强调)
若是表访问的类型为:
3 EQ_REF/REF_OR_NULL/REF/SYSTEM/CONST: 可使用ICP
4 range:若是不是“index tree only(只读索引)”,则有机会使用ICP
5 ALL/FT/INDEX_MERGE/INDEX_SCAN:  不可使用ICP


五 上楼spa

1 条件下推,一直是SQL优化的基本规则。因此,条件下推技术是常规技术。数据库的优化器几乎不会不实现条件下推优化。指针

2 技术层面,MySQL存在MySQL Server层和储存层,使得条件下推显得“有些割裂”。

3 非技术层面,MySQL之因此引入ICP,猜一猜或拍拍脑壳,缘由你懂得。


六 从代码的角度看

对于图一的解释,给出了读数据的代码片断,不管是关闭仍是打开ICP, 从下面给出的函数调用关系能够看出,2幅图对应的状况下,代码路径是一致的.

首条元组读取调用关系(蓝色标识和非首条元组不一样之处):

JOIN::exec()->do_select()->sub_select()->join_init_read_record()->rr_quick()->
  QUICK_RANGE_SELECT::get_next()->ha_innobase::multi_range_read_next()->
  DsMrr_impl::dsmrr_next()->handler::multi_range_read_next()->
  handler::read_range_first()->handler::ha_index_read_map()->
  handler::index_read_map()->ha_innobase::index_read()

 

除首条元组读取调用关系(蓝色标识和首条元组不一样之处)

JOIN::exec()->do_select()->sub_select()->join_init_read_record()->rr_quick()->
  QUICK_RANGE_SELECT::get_next()->ha_innobase::multi_range_read_next()->
  DsMrr_impl::dsmrr_next()->handler::multi_range_read_next()->
  handler::read_range_next()->handler::ha_index_next()->  ha_innobase::index_next()->ha_innobase::general_fetch()

相关文章
相关标签/搜索