通常大家都会根据查询的WHERE 条件来穿件合适的索引,不过这只是索引优化的一个方面。设计优秀的索引应该考虑到整个查询,而不单单是WHERE 条件部分。索引确实是一种查找数据的高效方式,但是MySQL也可以使用索引来直接获取列的数据,这样就不再需要读取数据行。如果索引的叶子节点已经包含要查询的数据,那么还有什么必要再返回表查询呢?如果一个索引包含(或者覆盖)所有需要查询的字段的值,我们就称之为“覆盖索引”。

  覆盖索引是非常有用的工具,能够极大的提高性能。考虑一下如果查询只需要索引而无需返回表,会带来多大好处:

  索引条目通常远小于数据行大小,所以只需要读取索引,那么MySQL就会极大的减少数据访问量。这对缓存的负载非常重要,因为这种情况下相应时间大部分花费在数据拷贝上。覆盖索引对于I/O密集型的应用也有帮助,以为索引比数据更小,更容易全部放入内存中(这对于MyIsam 尤其正确,因为myisam 能压缩索引以变得更小)。

  因为索引是按照列值顺序存储的(至少在单个页内是如此),所以对于IO密集型的范围查询会比随机从磁盘读取没以后数据的io要小的多。对于某些存储引擎,例如MyISAM,甚至可以通过OPTIMIZE命令使得索引完全顺序排列,这让简单的范围查询能使用完全顺序的索引访问。

  一些存储引擎如MyISAM,在内存中只缓存索引,数据则依赖操作系统来缓存,因此要访问数据需要一次系统调用。这可能会导致严重的性能问题,尤其是那些系统调用占了数据访问中的最大开销的场景。

  由于InnoDB的聚簇索引,覆盖索引对InnoDB表特别有用。InnoDB的二级索引在叶子节点中保存了行的主键值,所以如果二级主键能够覆盖查询,则可以避免对主键索引的二次查询。在所有这些场景中,索引中满足查询的成本一般比查询要小的多。

  不是所有的类型的索引都可以成为覆盖索引,覆盖索引必须要存储索引列的值,而哈希索引,空间索引和全文索引等都不存储引列的值,所以MySQL只能使用B-Tree索引做覆盖索引。另外不同的存储引擎实现覆盖索引的方式也不同,而且不是所有的覆盖索引都支持覆盖索引。

  当发起一个呗索引覆盖的查询(也叫索引覆盖查询)时,在EXPLAIN的Extra列可以看到“Using index”的信息。

  覆盖索引查询还有很多陷阱可能会导致无法实现优化。MySQL查询优化器会在执行查询前判断是否有一个索引能畸形覆盖。假设索引覆盖了WHERE条件中的字段,但不是整个查询涉及的字段。如果查询条件为假,MySQL5.5和更早的版本也总是会回表获取行,金凯并不需要这一行且最总会被过滤掉。

  有如下查询:

  SELECT * FROM produs WHERE actor="Bob" AND title LIKE"%A%"

  这里索引无法覆盖该查询,有两个原因:

  1 没有任何索引能够覆盖这个查询。因为查询从表中选择了所有的列,而没有任何索引覆盖了所有的列。不过,理论上MySQL还有一个捷径可以利用:WHERE条件中的列是有索引可以覆盖的,因此,MySQL可以使用该索引找到对应的actor 并检查title是否匹配,过滤之后再读取需要的数据行。

  2 MySQL不能再索引中执行LIKE操作。这是底层存储引擎API限制,MySQL5.5和更早的版本中只允许在索引中做简单的比较操作(例如,等于、大于、不等于)。MySQL能在索引中做最左前缀的like比较,因为该操作可以转换成为简单的比较操作,但是如果是通配符开头的LIKE 查询,存储引擎就无法比较匹配。这种情况下,MySQL服务职能提取数据行的值而不是索引值来作比较。

  也有办法解决上面所说的两个问题,需要重写查询并巧妙的设计索引。先将索引扩展至覆盖三个数据列(artist,title,prod_id)然后按照如下的方式重写查询。

  SELECT * FROM products JOIN(SELECT prod_id from products WHERE actor="BOB" and title like "%A%") AS t1 on (t1.pro_id = products.prod_id) .

  我们把这种方式叫做延迟关联(deferred join),因为延迟了对列的访问。在查询的第一阶段MySQL可以使用覆盖索引,在FROM 子句的子查询中找到匹配的prod_id,然后根据这prod_id值在外出查询匹配获取需要的所有列值。虽然无法使用索引覆盖整个查询,但总比完全无法利用索引覆盖的好。

  

  这样的优化效果取决于WHERE 条件匹配返回的行数,假设这个products表有100w行数据,我们来看一下上面两个查询在三个不同的数据集上的表现,每个数据集包含了100W行:

  第一个数据集:Bob 出演了3W部作品,其中有2W部标题中包含A

  第二个数据集:Bob..........3W.......,............40部..........

  第三个数据集:...............50部。。。。。。。。10部。。。。

  数据集    原查询    优化后查询

  1      每秒5次    每秒5次

  2      每秒7次    每秒35次

  3      每秒2400次  每秒2000次

  下面是对结果的分析:

  在实例1中,查询返回了一个很大的结果集,因此看不到优化的效果。大部分时间都花在读取和发送数据了。

  在实例2中,经过索引过滤,尤其是第二个条件过滤后只返回了很少的结果集,优化效果非常明显:在这个数据集上性能提高了5倍,优化后的查询的效率主要得益于读取40行完整的数据,而不是原查询的3W行。

  在实例3中,显示了子查询效率不高反而下降的情况。因为索引过滤时符合第一个条件的结果集已经很小,所以子查询带来的成本反而比从表中直接提取完整的行更高。

  在大多数存储引擎中,覆盖索引只能覆盖那些只访问索引中部分列的查询。不过,可以进一步优化InnoDB。回想一下,InnoDB 的二级索引的叶子节点都包含了主键的值,这意味着InnoDB的二级索引可以有效的利用这些额外的主键来覆盖查询。

  

  

MySQL 覆盖索引的更多相关文章

  1. Mysql覆盖索引与延迟关联

    延迟关联:通过使用覆盖索引查询返回需要的主键,再根据主键关联原表获得需要的数据.   为什innodb的索引叶子节点存的是主键,而不是像myisam一样存数据的物理地址指针? 如果存的是物理地址指针不 ...

  2. mysql覆盖索引与回表

    mysql覆盖索引与回表 Harri2012关注 62019.07.28 11:14:15字数 1,292阅读 77,322 select id,name where name='shenjian' ...

  3. mysql覆盖索引详解

    覆盖索引的定义: 如果一个索引包含(或覆盖)所有需要查询的字段的值,称为‘覆盖索引’.即只需扫描索引而无须回表. 只扫描索引而无需回表的优点:    1.索引条目通常远小于数据行大小,只需要读取索引, ...

  4. mysql覆盖索引(屌的狠,提高速度)

    话说有这么一个表: CREATE TABLE `user_group` ( `id` int(11) NOT NULL auto_increment, `uid` int(11) NOT NULL, ...

  5. mysql覆盖索引

    话说有这么一个表: CREATE TABLE `user_group` (   `id` int(11) NOT NULL auto_increment,   `uid` int(11) NOT NU ...

  6. Mysql覆盖索引 covering index 或者 index coverage

    组合索引 提到组合索引,大家都知道"最左前缀"原则.例如,创建索引 idx_name_age (name,age) ,通常情况下,where age=50 或者 where age ...

  7. mysql延迟查询, 覆盖索引使用例子

    引用自 'mysql高性能' 5.3.6章节 不能使用覆盖索引的情况 :  解决办法 : 

  8. 理解MySQL数据库覆盖索引

    话说有这么一个表: CREATE TABLE `user_group` ( `id` int(11) NOT NULL auto_increment, `uid` int(11) NOT NULL, ...

  9. MYSQL的全表扫描,主键索引(聚集索引、第一索引),非主键索引(非聚集索引、第二索引),覆盖索引四种不同查询的分析

    文章出处:http://inter12.iteye.com/blog/1430144 MYSQL的全表扫描,主键索引(聚集索引.第一索引),非主键索引(非聚集索引.第二索引),覆盖索引四种不同查询的分 ...

随机推荐

  1. Install FFmpeg, Mplayer, Mencoder, MP4Box, Flvtool2

    You can use the following tutorial to install ffmpeg and other video modules in your centos server.F ...

  2. Python自动化运维之11、面向对象基础

    一.简介 面向对象编程是一种编程方式,使用 “类” 和 “对象” 来实现,所以,面向对象编程其实就是对 “类” 和 “对象” 的使用.类就是一个模板,模板里可以包含多个方法(函数),方法里实现各种各样 ...

  3. IOS面试攻略

    IOS面试攻略(1.0) 2013-10-13 20:58:09|  分类: IOS面试 |  标签:ios知识点总汇  ios面试  |举报|字号 订阅     来自:伊甸网 @ 看到这个关键字,我 ...

  4. d3可视化实战03:神奇的superformula

    需求驱动实现 前文讲过了D3的数据驱动机制,中间所举的例子都很简单.例如那个demo里面,绑定的数据是一个简单的数组,实现的图元也仅仅是一堆用SVG画的circle.但是现实世界中我们往往会遇到复杂的 ...

  5. 摇滚吧HTML5!有声前端交互!(一)

    生命的伊始,婴儿用明亮的哭声宣告一个新生命的诞生,睁开双眼之前,一双小耳朵已经开始聆听这个世界.在如今的用户体验领域,几乎所有公司都会有视觉设计师,却鲜有注重听觉交互的公司.随着各大厂商对HTML5支 ...

  6. Moving Acerage

    http://zh.wikipedia.org/zh/%E7%A7%BB%E5%8B%95%E5%B9%B3%E5%9D%87

  7. Android 添加子视图(addView和setView)

    我们在添加视图文件的时候有两种方式,一种是通过在xml文件定义layout,另一种方式是在java代码中动态生成布局文件. 在xml中定义的layout要想转化为view,需要使用到LayoutInf ...

  8. COJ 0979 WZJ的数据结构(负二十一)

    WZJ的数据结构(负二十一) 难度级别:C: 运行时间限制:5000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 请你实现一个数据结构,完成这样的功能: 给你一个 ...

  9. Android 5.0 之SwipeRefreshLayout

    金田 下拉刷新是一种比较常用的效果,Android 5.0之前官方并未提供类似的控件,App中主要是用的第三方库,例如PullToRefresh,ActionBar-PullToRefresh等.刚好 ...

  10. 【转】Win8/8.1/Win7小技巧:揪出C盘空间占用的真凶

    原文网址:http://www.ithome.com/html/win8/55496.htm 不少使用Win8.Win8.1的用户不难发现,原先只占用20G大小的系统盘,随着使用时间的增加,C盘的磁盘 ...