作者:京东零售 孙涛

1.什么是掩盖索引

通常情况下,咱们创建索引的时候只重视where条件,不过这只是索引优化的一个方向。优异的索引规划应该纵观整个查询,而不仅仅是where条件部分,还应该重视查询所包含的列。索引确实是一种高效的查找数据方法,可是mysql也能够从索引中直接获取数据,这样就不在需要读数据行了。 掩盖索引(covering index) 指一个查询句子的执行只需要从辅佐索引中就能够得到查询记载,而不需要回表,去查询集合索引中的记载。能够称之为完成了索引掩盖。 在mysql数据库中,怎么看出一个sql是否完成了索引掩盖呢?



Mysql索引覆盖



从执行计划看,Extra的信息为using index ,即用到了索引掩盖。

2.掩盖索引为什么快

innodb存储引擎底层完成包括B+树索引和哈希索引,innodb存储引擎默许的索引模型/结构是B+树,所以大部分时候咱们使用的都是B+树索引,由于它良好的功能和特性更适合于构建高并发系统。根据索引的存储方法来划分,索引能够分为聚簇索引和非聚簇索引。聚簇索引的特点是叶子节点包含了完好的记载行,而非聚簇索引的叶子节点只需索引字段和主键ID。非聚簇索引中由于不含有完好的数据信息,查找完好的数据记载需要回表,所以一次查询操作实践上要做两次索引查询。而假如一切的索引查询都要经过两次才干查到,那么必定会引起功率下降,毕竟能少查一次就少查一次。

掩盖索引就完成了从非聚簇索引中直接获取数据,所以功率会提高。



Mysql索引覆盖



3.SQL优化场景

(1)无where条件

请看下面的sql



Mysql索引覆盖





Mysql索引覆盖



执行计划中,type为ALL,代表进行了全表扫描,扫描行数达到了26274308,所以执行时刻为9.25秒,也是正常的。

那么怎么优化?优化办法很简单,便是对查询列树立索引。如下,

alter table instance_space_history add index idx_org1(org1); 看增加索引后的执行计划



Mysql索引覆盖



Possible_keys为null,说明没有where条件时优化器无法经过索引检索数据;

可是看extra的信息 Using index,即从索引中获取数据,减少了读取的数据块的数量 。



Mysql索引覆盖



在看实践优化作用,扫描行数没变,可是使用了掩盖索引,查询时刻从9.25秒缩短到5.67秒。 考虑: 无where条件的查询,能够经过索引来完成索引掩盖查询。但前提条件是,查询回来的字段数足够少,更不用说select *之类的了。毕竟,树立key length过长的索引,始终不是一件好事情。

(2)where条件区分度低

使用区分度极低的字段作为where条件的查询SQL,关于dba或许研发人员优化一直是比较头疼的问题,这儿介绍一种思路,便是经过索引掩盖来优化 。 t_material_image是一张8亿多数据的大表,where条件的material_type字段区分度很低,下面是没加任何索引的执行计划和查询时刻(7.35秒)。



Mysql索引覆盖





Mysql索引覆盖



最简单想到的优化方法,便是给where条件的字段加索引,增加索引句子如下: alter table t_material_image add index idx_material_type (material_type);

再来看执行计划



Mysql索引覆盖



经过执行计划和测试成果看,的确是有作用的,可是走索引后的查询功率依然不能满意咱们期望。 然后试着给material_type,material_id增加联合索引。 alter table t_material_image add index idx_material_id_type (material_type,material_id);



Mysql索引覆盖





Mysql索引覆盖



从这个sql的执行计划看,出现Using index,完成了索引掩盖;再看执行时刻,功能得到了巨大的提高,竟然已经能够跑到0.85s左右了。

考虑:

当where条件字段区分度低(过滤性差),且where条件与查询字段总数较少的情况下,使用索引掩盖优化,是个不错的挑选。

(3)查询仅挑选主键

关于Innodb的辅佐索引,它的叶子节点存储的是索引值和指向主键索引的方位,然后需要经过主键在查询表的字段值,所以辅佐索引存储了主键的值。假如查询所挑选的列只需主键,应该考虑经过索引掩盖优化。 看下面的两个sql,字段 pin 和completion_time有联合索引,where条件不同只需comment_voucher_status = 0,可是执行时刻距离巨大(第一个sql0.58s,第二个sql0.2s),为什么呢?是不是很困惑



Mysql索引覆盖





Mysql索引覆盖





Mysql索引覆盖





Mysql索引覆盖



咱们来看执行计划,主要不同体现在extra,第一个sql用到Using index condition,而第二个sql用到Using index,由于pin和completion_time有联合索引,并且查询成果只挑选了主键id,所以第二个sql掩盖了一切的where条件字段和查询成果挑选字段,故完成了索引掩盖。 考虑:

当查询字段只需主键时,更简单完成索引掩盖,由于索引只需掩盖where条件,就能够完成索引掩盖。

4.总结与建议

索引的核心作用: (1)经过索引检索仅需要数据 (2)从索引中直接获取查询成果 索引掩盖的条件: (1)Select查询的回来列包含在索引列中 (2)有where条件时,where条件中要包含索引列或复合索引的前导列 (3)查询成果的总字段长度能够承受