ICP,Index Condition Pushdown

理解ICP特性前,先去前面理解MRR特性,了解where条件中的三阶段提取: index key、index filter、table filter。

传送门:SQL 执行过程和where条件提取过程

MySQL 5.6以上支持,在index filter阶段生效。是一种使用索引从表中检索行数据的优化方式。

被ICP优化时,执行计划显示Using index condition

ICP作用

  • 减小server层数据集,减少数据传输,提高处理效率。

  • ICP能减少引擎层访问基表的次数和  Server层访问存储引擎的次数。减少从基表中读取操作的数量,在引擎层面对索引列条件进行更多的提取,从而降低IO操作。

  • 支持range、ref、eq_ref、eq_or_null类型查询。

    传送门: 类型及执行计划

ICP原理

  • 在有ICP以前是把index key过滤后的全部记录(数据集较大)丢给server层进行index filter、table filter过滤。
  • ICP特性可以把index filter过程下推(pushdown)到引擎层进行过滤,再将过滤后的(数据集较小)数据在server层进行table filter过滤。这样就减少了回表与返回MySQL Server层的记录交互开销,提高了SQL的执行效率。

MySQL特性:ICP,Index Condition Pushdown_MySQL

ICP特点

  • MySQL 5.6中只支持 MyISAM、InnoDB、NDB cluster
  • 从MySQL 5.7.3开始支持分区表的ICP
  • 不支持主建索引的ICP(对于Innodb的聚集索引,完整的记录已经被读取到Innodb Buffer,此时使用ICP并不能降低IO操作)——也就是说:对于InnoDB表,ICP只适用于辅助索引
  • 当 SQL 使用覆盖索引时但只检索部分数据时,ICP 无法使用
  • ICP的加速效果取决于在存储引擎内通过ICP筛选掉的数据的比例

ICP启用参数及依赖

  • 数据库配置 optimizer_switch="index_condition_pushdown=on”;

ICP使用场景举例

无ICP时的执行过程

  • 场景1

    [SQL 执行过程和where条件提取过程](./4.0.SQL 执行过程和where条件提取过程.md)

    (a,b,c)
    select * from t where a=1 and b>=1 and b10;
    
    引擎层:index key , 
    // index first key //
    // 索引第一个键a有 = 或 >= 吗?有,a=1。读取索引下一个键。
    // 下一个键b有 = 或 >= 吗?有,b>= 1。读取索引下一个键。
    // 下一个键c有 = 或 >= 吗?没有。有 > 吗?有,c>10。结束first key提取。
    // 最终first key = (a=1,b>=1,c>10)
    // index last ket //
    // 索引第一个键a为 = ,跳过第一个键,读取索引下一个键。
    // 索引第二个键b有 <= 吗?有,b <= 10。读取索引下一个键。
    // 索引第三个键c没有范围结束值,结束提取。
    // 最终last key = (b=1 and b10 归给index filter了。
    
    最终,index filter为c>10
    [1,1]
    [1,2]
    
    总结一下,就是引擎层使用index key筛选出10条结果给server层,server层通过index filter筛选出2条结果。
  • 场景2

    通过二级索引中的值去表中取出所有a=1& b>=1&b

    (a,b,c)
    select * from t where a=1 and b>=1 and b10 and d='a';
    
    引擎层:index key , 
    // index first key //
    // 索引键第一键a为等值,a=1,继续读取下一个索引键。
    // 索引键第二键b为范围值,b>=1,继续读取下一个索引键。
    // 索引键第三键c为范围值,c>10。遇到第一个 > 逻辑,结束first key的提取。
    // index last key //
    // 索引键第一键a为等值,继续读取下一个索引键。
    // 索引键第二键b的范围结束值为 b=1 and b10 )
    [1,1]
    ..
    [1,10]
    10 rows
    
    然后将这10条结果返回给server层。
    
    server层:index filter,
    // 根据where条件提取规则,索引第一列为等值&索引第二列条件为范围,则跳过这两列(被index key拿走了),然后将其他*所有属于索引键的条件*都归给server层进行index filter。
    // c列属于索引键,d列无索引,因此只有c>10归给server层进行index filter。
    
    最终,index filter为 c>10
    [1,1]
    [1,2]
    
    server层:table filter, 
    // 其他所有不属于索引键的条件都归给server层进行table filter
    // 这里只有d='a'了。
    
    最终,table filter为d='a'
    [1,1]
    
    总结一下,就是 引擎层筛选10条结果给server层,server层进行index filter后筛选出2条结果,再由server层进行table filter,得出最终结果——1条。

ICP特性下的过程

Index Condition Pushdown

各环节提取逻辑和流程没有变化,区别只是index filter发生在引擎层面,不在server层面实现。

  • 场景1 via ICP

    (a,b,c)
    select * from t where a=1 and b>=1 and b10;
    
    引擎层:index key , a=1 and b>=1 and b10
    [1,1]
    
    ~~server层:index filter, c>10~~就不需要了
    总结一下,就是引擎层返回给server层1条结果,结束。
  • 场景2 via ICP

    (a,b,c)
    select * from t where a=1 and b>=1 and b10 and d='a';
    
    引擎层:index key , a=1 and b>=1 and b10
    [1,1]
    [1,2]
    
    server层:table filter, d='a'
    [1,1]
    
    总结一下,就是引擎层返回给server层2条结果,server层进行table filter,得出1条结果。

通过案例对比可以发现,ICP特性减少了从引擎层到server层之间不必要的数据结果传输,因此效率更高。