使用一张用户表t_user
,表里创建联合索引(name, age)。
如果现在有一个需求:检索出表中名字第一个字是张,而且年龄是10岁的所有用户
。那么,SQL语句是这么写的:
复制代码
select * from tuser where name like '张%' and age=10;
假如你了解索引最左匹配原则,那么就知道这个语句在搜索索引树的时候,只能用 张
,找到的第一个满足条件的记录id为1。
那接下来的步骤是什么呢?
没有使用ICP
在MySQL 5.6之前,存储引擎根据通过联合索引找到name like '张%'
的主键id(1、4),逐一进行回表扫描,去聚簇索引找到完整的行记录,server层再对数据根据age=10进行筛选
。
我们看一下示意图:
可以看到需要回表两次,把我们联合索引的另一个字段age
浪费了。
使用ICP
而MySQL 5.6 以后, 存储引擎根据(name,age)联合索引,找到name like '张%'
,由于联合索引中包含age
列,所以存储引擎直接再联合索引里按照age=10
过滤。按照过滤后的数据再一一进行回表扫描。
我们看一下示意图:
可以看到只回表了一次。
除此之外我们还可以看一下执行计划,看到Extra
一列里Using index condition
,这就是用到了索引下推。
索引下推使用条件
- 只能用于
range
、ref
、eq_ref
、ref_or_null
访问方法; - 只能用于
InnoDB
和MyISAM
存储引擎及其分区表; - 对
InnoDB
存储引擎来说,索引下推只适用于二级索引(也叫辅助索引);
索引下推的目的是为了减少回表次数,也就是要减少IO操作。对于
InnoDB
的聚簇索引来说,数据和索引是在一起的,不存在回表这一说。
- 引用了子查询的条件不能下推;
- 引用了存储函数的条件不能下推,因为存储引擎无法调用存储函数。
相关系统参数
索引条件下推默认是开启的,可以使用系统参数optimizer_switch
来控制器是否开启。
查看默认状态:select @@optimizer_switch