Mysql索引覆盖

京东云开发者
• 阅读 555
作者:孙涛

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)查询结果的总字段长度可以接受

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
3年前
MySQL千万级别优化·中
MySQL千万级别的查询优化手段·中单列索引(假设在v\_record表中存在id列的索引)1、WHERE条件使用​EXPLAINSELECT\FROMv\_recordWHEREid2​结论:利用索引进行回表查询2、SELECT字段使用
Wesley13 Wesley13
3年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
PHP创建多级树型结构
<!lang:php<?php$areaarray(array('id'1,'pid'0,'name''中国'),array('id'5,'pid'0,'name''美国'),array('id'2,'pid'1,'name''吉林'),array('id'4,'pid'2,'n
Wesley13 Wesley13
3年前
mysql5.6 分页查询优化
mysql5.6分页查询优化场景:表结构:主键(非自增)contentCode(varchar),过滤条件列为updateTime(timeStamp),已经为timestamp建立索引。搜索sql为:SELECTFROMmy_hello_tableWHEREupdat
Wesley13 Wesley13
3年前
mysql之索引
一.索引:索引是表的目录,在查找内容之前可以先在目录中查找索引位置,以此快速定位查询数据。对于索引,会保存在额外的文件中1.1.创建一个索引:mysqlcreateindexix_classontb3(class_id);QueryOK,0rowsaffected(0.02sec)
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Stella981 Stella981
3年前
ELK学习笔记之ElasticSearch的索引详解
0x00ElasticSearch的索引和MySQL的索引方式对比Elasticsearch是通过Lucene的倒排索引技术实现比关系型数据库更快的过滤。特别是它对多条件的过滤支持非常好,比如年龄在18和30之间,性别为女性这样的组合查询。倒排索引很多地方都有介绍,但是其比关系型