MySQL · myrocks · myrocks index condition pushdown

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
云原生数据库 PolarDB 分布式版,标准版 2核8GB
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: index condition pushdownIndex condition pushdown(ICP)是直到mysql5.6才引入的特性,主要是为了减少通过二级索引查找主键索引的次数。目前ICP相关的文章也比较多,本文主要从源码角度介绍ICP的实现。讨论之前,我们先再温习下。以下图片来自mariadb 引入ICP之前 引入ICP之后 再来看个例

index condition pushdown

Index condition pushdown(ICP)是直到mysql5.6才引入的特性,主要是为了减少通过二级索引查找主键索引的次数。目前ICP相关的文章也比较多,本文主要从源码角度介绍ICP的实现。讨论之前,我们先再温习下。

以下图片来自mariadb

  • 引入ICP之前
    screenshot.png

  • 引入ICP之后
    screenshot.png

再来看个例子

CREATE TABLE `t1` (
  `a` int(11) DEFAULT NULL,
  `b` char(8) DEFAULT NULL,
  `c` int(11) DEFAULT '0',
  `pk` int(11) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`pk`),
  KEY `idx1` (`a`,`b`)
) ENGINE=ROCKSDB;
INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b'),(3,'c');
INSERT INTO t1 (a,b) VALUES (4,'a'),(4,'b'),(4,'c'),(4,'d'),(4,'e'),(4,'f');

set optimizer_switch='index_condition_pushdown=off';

## 关闭ICP(Using where)
explain select * from t1 where a=4 and b!='e';
+----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type  | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | t1    | range | idx1          | idx1 | 14      | NULL |    2 | Using where |
+----+-------------+-------+-------+---------------+------+---------+------+------+-------------+

## 关闭ICP走cover index(Using where; Using index)
explain select a,b from t1 where a=4 and b!='e';
+----+-------------+-------+------+---------------+------+---------+-------+------+--------------------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref   | rows | Extra                    |
+----+-------------+-------+------+---------------+------+---------+-------+------+--------------------------+
|  1 | SIMPLE      | t1    | ref  | idx1          | idx1 | 5       | const |    4 | Using where; Using index |
+----+-------------+-------+------+---------------+------+---------+-------+------+--------------------------+

set optimizer_switch='index_condition_pushdown=on';

## 开启ICP(Using index conditione)
explain select * from t1 where a=4 and b!='e';
+----+-------------+-------+-------+---------------+------+---------+------+------+-----------------------+
| id | select_type | table | type  | possible_keys | key  | key_len | ref  | rows | Extra                 |
+----+-------------+-------+-------+---------------+------+---------+------+------+-----------------------+
|  1 | SIMPLE      | t1    | range | idx1          | idx1 | 14      | NULL |    2 | Using index condition |
+----+-------------+-------+-------+---------------+------+---------+------+------+-----------------------+

## 开启ICP仍然是cover index(Using where; Using index)
explain select a,b from t1 where a=4 and b!='e';
+----+-------------+-------+------+---------------+------+---------+-------+------+--------------------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref   | rows | Extra                    |
+----+-------------+-------+------+---------------+------+---------+-------+------+--------------------------+
|  1 | SIMPLE      | t1    | ref  | idx1          | idx1 | 5       | const |    4 | Using where; Using index |
+----+-------------+-------+------+---------------+------+---------+-------+------+--------------------------+

这里总结下ICP的条件

server层主要负责判断是否符合ICP的条件,符合ICP则把需要的condition push到engine层。
engine层通过二级索引查找数据时,用server层push的condition再做一次判断,如果符合条件才会去查找主索引。

目前mysql支持ICP的引擎有MyISAM和InnoDB,MyRocks引入rocksdb后,也支持了ICP。
server层实现是一样的,engine层我们主要介绍innodb和rocksdb的实现。

server层

关键代码片段如下

make_join_readinfo()
  
switch (tab->type) {
    case JT_EQ_REF:
    case JT_REF_OR_NULL:
    case JT_REF:
      if (tab->select)
        tab->select->set_quick(NULL);
      delete tab->quick;
      tab->quick=0;
      /* fall through */
    case JT_SYSTEM:
    case JT_CONST:
      /* Only happens with outer joins */
      if (setup_join_buffering(tab, join, options, no_jbuf_after,
                               &icp_other_tables_ok))
        DBUG_RETURN(true);
      if (tab->use_join_cache != JOIN_CACHE::ALG_NONE)
        tab[-1].next_select= sub_select_op;

      if (table->covering_keys.is_set(tab->ref.key) &&
          !table->no_keyread)
        table->set_keyread(TRUE);
      else
        push_index_cond(tab, tab->ref.key, icp_other_tables_ok,
                        &trace_refine_table);
      break;

从代码中看出只有符合的类型rangerefeq_ref, and ref_or_null 二级索引才可能会push_index_cond。

而这里通过covering_keys来判断并排除使用了cover index的情况。covering_keys是一个bitmap,保存了所有可能用到的覆盖索引。在解析查询列以及条件列时会设置covering_keys,详细可以参考setup_fields,setup_wild,setup_conds。

engine层

innodb

innodb在扫描二级索引时会根据是否有push condition来检查记录是否符合条件(row_search_idx_cond_check)
逻辑如下:

row_search_for_mysql()
......
  if (prebuilt->idx_cond)
  {
      row_search_idx_cond_check //检查condition
      row_sel_get_clust_rec_for_mysql //检查通过了才会去取主索引数据
  }
....

典型的堆栈如下

handler::compare_key_icp
innobase_index_cond
row_search_idx_cond_check
row_search_for_mysql
ha_innobase::index_read
ha_innobase::index_first
ha_innobase::rnd_next
handler::ha_rnd_next
rr_sequential
join_init_read_record
sub_select
do_select

rocksdb

rocksdb在扫描二级索引时也会根据是否有push condition来检查记录是否符合条件

逻辑如下

read_row_from_secondary_key()
{
   find_icp_matching_index_rec//push了condition才会检查condition
   get_row_by_rowid//检查通过了才会去取主索引数据
}

典型的堆栈如下

handler::compare_key_icp
myrocks::ha_rocksdb::check_index_cond
myrocks::ha_rocksdb::find_icp_matching_index_rec 
myrocks::ha_rocksdb::read_row_from_secondary_key 
myrocks::ha_rocksdb::index_read_map_impl 
myrocks::ha_rocksdb::read_range_first
handler::multi_range_read_next 

other

ICP对cover index作出了严格的限制,而实际上应该可以放开此限制,这样可以减少enging层传第给server层的数据量,至少可以减少server层的内存使用。欢迎指正!

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
11月前
|
存储 SQL 缓存
一文带你了解MySQL之Adaptive Hash Index
在InnoDB体系架构图的内存结构中,还有一块区域名为:Adaptive Hash Index,翻译成中文:自适应哈希索引,缩写:AHI,它是一个纯内存结构,我们今天就来了解它。
757 0
|
5月前
|
关系型数据库 MySQL 数据库
Mysql中key与index区别
Mysql中key与index区别
|
6月前
|
存储 SQL 关系型数据库
MySQL 优化 index merge(索引合并)引起的死锁分析(强烈推荐)
生产环境出现死锁流水,通过查看死锁日志,看到造成死锁的是两条一样的update语句(只有where条件中的值不同),如下:
|
9月前
|
关系型数据库 MySQL 索引
不会2023年你还不知道Mysql中index、primary key、unique key、foreign key是什么和如何创建吧?
不会2023年你还不知道Mysql中index、primary key、unique key、foreign key是什么和如何创建吧?
59 0
|
11月前
|
关系型数据库 MySQL 索引
MySQL 8 不可见索引 invisible index
不可见索引 创建不可见索引
|
11月前
|
关系型数据库 MySQL 索引
MySQL - 索引下推 Index Condition Pushdown 初探
MySQL - 索引下推 Index Condition Pushdown 初探
67 0
|
11月前
|
存储 关系型数据库 MySQL
MySQL的索引条件下推(index condition pushdown,ICP)
索引下推:不符合索引最左前缀原则,却还能利用复合索引的其他字段,减少回表次数。 最左前缀可用于在索引中定位记录。那不符合最左前缀的部分,会怎样
74 0
|
存储 关系型数据库 MySQL
简述 MySQL 的主键 PRIMARY KEY 和唯一键 UNIQUE INDEX
简述 MySQL 的主键 PRIMARY KEY 和唯一键 UNIQUE INDEX
255 0
简述 MySQL 的主键 PRIMARY KEY 和唯一键 UNIQUE INDEX
|
关系型数据库 MySQL C#
【C#】【MySQL】【GridView】删除出现Parameter index is out of range
【C#】【MySQL】【GridView】删除出现Parameter index is out of range
94 0
【C#】【MySQL】【GridView】删除出现Parameter index is out of range
|
存储 缓存 算法
InnoDB & index页-mysql详解(二)
InnoDB & index页-mysql详解(二)

相关产品

  • 云数据库 RDS MySQL 版