InnoDB ICP 代码路径

本文简单记录下和Index Condition Pushdown相关的代码路径

涉及的代码只包含InnoDB层

当MySQL使用索引进行数据检索时,不可用于在Innodb进行索引检索的WHERE条件,也可以下推到Innodb层,以减少回表查询的数据量

#对于innodb表,ICP只应用于二级索引

#在MySQL5.6里还不支持对分区表ICP(5.7支持)

MySQL版本:5.7.5

1.创建测试表

create table t1 (a int auto_increment primary key, b int, c int, d int, key(b,c));

生成数据:

insert into t1(b,c,d) select rand()*100, rand()*1000, rand()*10000;

insert into t1(b,c,d) select rand()*100, rand()*1000, rand()*10000 from t1;

insert into t1(b,c,d) select rand()*100, rand()*1000, rand()*10000 from t1;

……

root@sb1 01:57:06>explain select * from t1 where b = 90 and c > 500\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t1
partitions: NULL
type: range
possible_keys: b
key: b
key_len: 10
ref: NULL
rows: 168
filtered: 100.00
Extra: Using index condition
1 row in set, 1 warning (0.00 sec)

Tips: 从MySQL5.7.3开始,explain的输出增加了两列:partitions用户分区表的查询优化的分区选择,filtered表示根据当前查询计划的过滤性百分比,计算方式参考函数Explain_join::explain_rows_and_filtered()

1.optimizer确认是否可以ICP

堆栈:

handle_select –> mysql_select –> mysql_prepare_and_optimize_select

–> JOIN::optimize –> make_join_readinfo

–> QEP_TAB::push_index_cond

–> ha_innobase::idx_cond_push // 初始化icp的条件pushed_idx_cond 和使用到的索引号pushed_idx_cond_keyno,设置标记in_range_check_pushed_down为true

根据函数QEP_TAB::push_index_cond的注释,只有满足如下条件时,才会使用ICP:

/*
We will only attempt to push down an index condition when the
following criteria are true:
0. The table has a select condition
1. The storage engine supports ICP.
2. The system variable for enabling ICP is ON.
3. The query is not a multi-table update or delete statement. The reason
for this requirement is that the same handler will be used
both for doing the select/join and the update. The pushed index
condition might then also be applied by the storage engine
when doing the update part and result in either not finding
the record to update or updating the wrong record.
4. The JOIN_TAB is not part of a subquery that has guarded conditions
that can be turned on or off during execution of a ‘Full scan on NULL
key’.
@see Item_in_optimizer::val_int()
@see subselect_single_select_engine::exec()
@see TABLE_REF::cond_guards
@see setup_join_buffering
5. The join type is not CONST or SYSTEM. The reason for excluding
these join types, is that these are optimized to only read the
record once from the storage engine and later re-use it. In a
join where a pushed index condition evaluates fields from
tables earlier in the join sequence, the pushed condition would
only be evaluated the first time the record value was needed.
6. The index is not a clustered index. The performance improvement
of pushing an index condition on a clustered key is much lower
than on a non-clustered key. This restriction should be
re-evaluated when WL#6061 is implemented.
*/

ha_innobase::build_template

// 初始化prebuilt的idx_cond, 如果使用ICP,指向ha_innobase对象,否则为NULL,后续根据该列是否为NULL来判定

// 初始化prebuilt->idx_cond_n_cols,即使用到的索引列条件列数

2. 检查ICP条件

当从二级索引检索到数据时,需要根据icp条件进行记录过滤

堆栈:

ha_innobase::index_read

|–>row_search_mvcc

|–>row_search_idx_cond_check //当读取到一条合法的二级索引记录后,需要进行下推条件检查

// 将读取到的二级索引记录上,作为condition的列值转换为MySQL Format

// innobase_index_cond:判断是否满足索引条件

// 当满足索引条件时,如果无需回聚集索引查询,则将剩余的索引记录直接转换成MySQL Format

|–> row_sel_get_clust_rec_for_mysql //当找到满足条件的二级索引记录时,再根据其查询对应的聚集索引记录

时间: 2024-05-25 03:33:08

InnoDB ICP 代码路径的相关文章

asp.net(C#)并非所有的代码路径都返回值

问题描述 asp.net(C#)并非所有的代码路径都返回值 public bool IsExist(string artNo1) { string artNo; List<string> list_artNo = new List<string>(); foreach (GridViewRow rows in GridView1.Rows) { artNo = rows.Cells[0].Text; list_artNo.Add(artNo); } foreach (string

radiobutton-函数不会在所有代码路径上都返回值。当使用结果时,可能会在运行时发生 null 引用异常

问题描述 函数不会在所有代码路径上都返回值.当使用结果时,可能会在运行时发生 null 引用异常 函数代码为: Function result_ss() As String If RadioButton_ss1.Checked = True Then result_ss = "1" If RadioButton_ss2.Checked = True Then result_ss = "2" End Function 求大神帮忙 解决方案 Function resul

c# 方法 foreach-C#并非所有的代码路径都返回值

问题描述 C#并非所有的代码路径都返回值 public static string aa(string a) { string str; if (str == "") { MessageBox.Show("请输入..."); return null; } else { string[] split = Regex.Split(str, ";", RegexOptions.IgnoreCase); foreach (string s in spli

方法-C# 并非所有的代码路径都返回值

问题描述 C# 并非所有的代码路径都返回值 public static string aa(string a) { if (a == "") { MessageBox.Show("请输入..."); return null; } else { string[] split = Regex.Split(a, ";", RegexOptions.IgnoreCase); foreach (string s in split) { return s;

在线等,并非所有的代码路径都返回值问题

问题描述 for(intm=0;m<alSchedule.Count;m++){if(schedule.Equals(alSchedule[m])){returntrue;}else{returnfalse;}} alSchedule是一个存放数组的List<int[]>List用来判断数组list是否存在一个数组schedule没发现什么错误啊.... 解决方案 解决方案二:for(intm=0;m<alSchedule.Count;m++){if(schedule.Equals

Multi Range Read 代码路径

所谓MRR,简单的说就是当使用二级索引进行检索并且查询的列需要回表时,先根据检索到的PK值进行排序,然后再回表依次查询聚集索引,从而避免过多的随机IO. 测试示例: 创建一个简单的表: CREATE TABLE `x1` ( `a` int(11) NOT NULL AUTO_INCREMENT, `b` int(11) DEFAULT NULL, `c` int(11) DEFAULT NULL, PRIMARY KEY (`a`), KEY `b` (`b`) ) ENGINE=InnoDB

错误 1 “admin_TeacherInfo.GetKmName(int)”: 并非所有的代码路径都返回值

问题描述 求教高手这个是什么原因,要怎么样改....错误代码如下:publicstringGetKmName(intnum){SqlConnectionconn=BaseClass.DBCon();conn.Open();SqlCommandcmd=newSqlCommand("selectLessonNamefromtb_LessonwhereID="+num,conn);try{stringkname=cmd.ExecuteScalar().ToString();returnkna

qt代码默认路径是什么

问题描述 qt代码默认路径是什么 我自己安装时修改了默认代码路径,后来缺少动态链接库不能晕星期,想要改到安装目录下,求大神告知一下,感激不尽啊 解决方案 c:program files里面找找,或者全盘搜索下.你也可以在快捷方式上点右键-属性,里面有路径. 解决方案二: 你随便在一个目录下创建文件夹,把qt代码安装在该目录下就好了呀,我的是Linux,然后放在/home目录下

InnoDB foreign key 实现

本文是对Innodb外键实现代码路径的简单记录,对外键实现逻辑熟悉的同学直接忽略吧..... 前言 外键代表两张表之间的引用约束关系:在子表上出现的列记录,必须在父表上已经存在.通过外键,我们可以确保业务上的逻辑一致性,同时还能实现一些级联操作:MySQL目前只有InnoDB引擎支持外键,类似MyISAM.Tokudb等引擎都不支持外键. InnoDB支持建立多个列的外键,但被外键约束的父表上必须对这些列建立索引,并且子表上的外键列 和父表上索引上的顺序是一致的.默认情况下,当删除父表中被外键约