索引覆盖
覆盖索引(covering index)指一个查询语句的执行只用从索引中就能够取得,不必从数据表中读取。也可以称之为实现了索引覆盖。
当一条查询语句符合覆盖索引条件时,MySQL只需要通过索引就可以返回查询所需要的数据,这样避免了查到索引后再返回表操作,减少I/O提高效率。
如,表covering_index_sample中有一个普通索引 idx_key1_key2(key1,key2)。
当我们通过SQL语句:
select key2 from covering_index_sample where key1 = ‘keytest’;
的时候,就可以通过覆盖索引查询,无需回表。
但是以下SQL,因为不符合最左前缀匹配,虽然是索引覆盖,但是也无法用到索引(会扫描索引树):
select key1 from covering_index_sample where key2 = ‘keytest’;
但是如果SQL中查询的信息不包含在联合索引中,那么就不会走索引覆盖。如:
select key2,key3 from covering_index_sample where key1 = ‘keytest’;
索引下推
当对联合索引进行范围查询的时候,会导致后面的索引列失效,从而需要回表数据交给server层进行条件判断,索引下推解决的问题是 在引擎层直接对未生效的索引列进行条件判断,从而减少回表次数提高效率
没有使用ICP
可以看到需要回表两次,把我们联合索引的另一个字段age浪费了。
使用ICP
而MySQL 5.6 以后, 存储引擎根据(name,age)联合索引,找到,由于联合索引中包含列,所以存储引擎直接再联合索引里按照age=10过滤。按照过滤后的数据再一一进行回表扫描。
我们看一下示意图:
可以看到只回表了一次。
除此之外我们还可以看一下执行计划,看到Extra一列里 Using index condition,这就是用到了索引下推。
索引下推不止like
上面的例子中,提到了like,包括MySQL官网中也只提到了like,但是其实不止有Like。
因为我认为索引下推其实是解决索引失效带来的效率低的问题的一种手段。
所以当联合索引中,某个非前导列因为索引失效而要进行扫表并回表时,就可以进行索引下推优化了。
如,有a,b联合索引,类型都是varchar,以下SQL也可以用到索引下推:
select d from t2 where a = "ni" and b = 1;
因为b字段因为类型不匹配导致索引失效了,但是通过下推优化其实是可以减少回表的次数的。