MySQL索引使用

一、索引的利处
很多朋友对数据库中的索引的认识可能主要还是只限于“能够提高数据检索的效率,降低数据库的IO成本”。

确实,在数据库中个表的某个字段创建索引,所带来的最大益处就是将该字段作为检索条件的时候可以极大的提高检索效率,加快检索时间,降低检索过程中所需要读取的数据量。但是索引所给我们带来的收益只是提高表数据的检索效率吗?当然不是,索引还有一个非常重要的用途,那就是降低数据的排序成本。

我们知道,每个索引中索引数据都是按照索引键键值进行排序后存放的,所以,当我们的Query语句中包含排序分组操作的时候,如果我们的排序字段和索引键字段刚好一致,MySQL Query Optimizer就会告诉mysqld在取得数据之后不用排序了,因为根据索引取得的数据已经是满足客户的排序要求。

那如果是分组操作呢?分组操作没办法直接利用索引完成。但是分组操作是需要先进行排序然后才分组的,所以当我们的Query语句中包含分组操作,而且分组字段也刚好和索引键字段一致,那么mysqld同样可以利用到索引已经排好序的这个特性而省略掉分组中的排序操作。

排序分组操作主要消耗的是我们的内存和CPU资源,如果我们能够在进行排序分组操作中利用好索引,将会极大的降低CPU资源的消耗。

二、索引的弊端
索引是完全独立于基础数据之外的一部分数据。

我们在insert和update操作索引字段时,会有额外的资源消耗。

三、如何判定是否需要创建索引
1、较频繁的作为查询条件的字段应该创建索引
提高数据查询检索的效率最有效的办法就是减少需要访问的数据量,从上面所了解到的索引的益处中我们知道了,索引正是我们减少通过索引键字段作为查询条件的Query的IO量的最有效手段。所以一般来说我们应该为较为频繁的查询条件字段创建索引。

2、唯一性太差的字段不适合单独创建索引,即使频繁作为查询条件
唯一性太差的字段主要是指哪些呢?如状态字段,类型字段等等这些字段中存方的数据可能总共就是那么几个几十个值重复使用,每个值都会存在于成千上万或是更多的记录中。

不仅如此,如果一个键值对应了太多的数据记录,也就是说通过该键值会返回占整个表比例很大的记录的时候,由于根据索引扫描产生的都是随机IO,其效率比进行全表扫描的顺序IO的效率要差很多,即使不会出现重复IO的读取,同样会造成整体IO性能的下降。

很多比较有经验的Query调优专家经常说,当一条Query所返回的数据超过了全表的15%的时候,就不应该再使用索引扫描来完成这个Query了。对于“15%”这个数字我们并不能判定是否很准确,但是之少侧面证明了唯一性太差的字段并不适合创建索引。

3、更新非常频繁的字段不适合创建索引
索引中的字段被更新的时候,不仅仅需要更新表中的数据,同时还要更新索引数据,以确保索引信息是准确的。这个问题所带来的是IO访问量的较大增加,不仅仅影响更新Query的响应时间,还会影响整个存储系统的资源消耗,加大整个存储系统的负载。

4、不会出现在WHERE子句中的字段不该创建索引
懂得都懂

四、单键索引还是组合索引
1、不用组合索引,创建多个单键索引会怎么样?
我们可以将WHERE子句中的每一个字段都创建一个单键索引。但是这样真的有效吗?在这样的情况下,MySQL Query Optimizer大多数时候都只会选择其中的一个索引,然后放弃其他的索引。即使他选择了同时利用两个或者更多的索引通过INDEX_MERGE来优化查询,可能所收到的效果并不会比选择其中某一个单键索引更高效。
MySQL会选择其中的一个索引。

2、组合索引
我们创建组合索引并不是说就需要将查询条件中的所有字段都放在一个索引中,我们还应该尽量让一个索引被多个Query语句所利用,尽量减少同一个表上面索引的数量,减少因为数据更新所带来的索引更新成本,同时还可以减少因为索引所消耗的存储空间。

五、Query的索引选择
在有些场景下,我们的Query由于存在多个过滤条件,而这多个过滤条件可能会存在于两个或者更多的索引中。在这种场景下,MySQL Query Optimizer一般情况下都能够根据系统的统计信息选择出一个针对该Query最优的索引完成查询,但是在有些情况下,可能是由于我们的系统统计信息的不够准确完整,也可能是MySQL Query Optimizer自身功能的缺陷,会造成他并没有选择一个真正最优的索引而选择了其他查询效率较低的索引。在这种时候,我们就不得不通过人为干预,在Query中增加Hint提示MySQL Query Optimizer告诉他该使用哪个索引而不该使用哪个索引,或者通过调整查询条件来达到相同的目的。

六、选择合适索引的几点建议
1、对于单键索引,尽量选择针对当前Query过滤性更好的索引;

2、在选择组合索引的时候,当前Query中过滤性最好的字段在索引字段顺序中排列越靠前越好;

3、在选择组合索引的时候,尽量选择可以能够包含当前Query的WHERE子句中更多字段的索引;

4、尽可能通过分析统计信息和调整Query的写法来达到选择合适索引的目的而减少通过使用Hint人为控制索引的选择,因为这会使后期的维护成本增加,同时增加维护所带来的潜在风险。