创建高性能的索引

索引的优点

  1. 减少扫描的数据了
  2. 避免排序和临时表
  3. 将随机IO变为顺序IO

三星系统:索引将相关记录放在一起;索引中的数据顺序和查找中的数据顺序一致;索引中的列包含了查询中需要的全部列。

高性能的索引策略

独立的列

如果查询中的列不是独立的(索引的列不能是表达式的一部分或者函数的参数),则mysql不会使用索引。

这个查询
select actor_id from sakila.actor where actor_id + 1 = 5;

前缀索引和索引的选择性

当需要索引很长的字符列的时候,一种可以模拟hash索引;另一种是索引开始的部分字符,这样可以大大节约索引空间,提高索引效率。

索引选择性,指的是不重复的索引值和记录总数(#T)的比值,范围从1/#T到1之间。索引选择性越高查询效率越高,因为mysql可以通过它过滤掉更多的行。唯一索引的选择性是1,性能最好。

一般情况,某个列前缀的选择性也足够高,对应blob,text和很长的varchar,必须使用。mysql也不允许索引这些列的完整长度。因此关键在于选择前缀的长度,使其基数接近于整个列的基数。

  1. 首先计算该字符列的count
  2. 然后逐一测试left(column,num)的count,其中column是列,num是前缀长度;即比较各个前缀长度的count是否和第一步中的count相似。

另一种方法是计算完整列的选择性,并使前缀的选择性接近于完整列的选择性。

select count(distinct city)/count(*) from city_demo;
select count(distinct left(city,3)/count(*) as sel3,    #0.0239
        count(distinct left(city,4)/count(*) as sel4,    #0.0293
        count(distinct left(city,5)/count(*) as sel5,    #0.02305
        count(distinct left(city,6)/count(*) as sel6,    #0.0309
        count(distinct left(city,7)/count(*) as sel7,    #0.0310
from city_demo;

这个测试发现完整列的选择性是0.0312,所以当前缀选择性接近0.031的时候,基本就可用了。所以7的时候就可用了。如果再增加,提升的幅度已经就很小了。

在考虑平均选择性的同时,有例外情况,需要考虑最坏情况下的选择性。即如果数据分布很不均匀,前缀效果会降低。比如上诉例子中长度为4的前缀,就可能出现不均的情况。实际中,如果地名用长度为4的前缀,以San和New开头的城市的选择性会很差,因为以这些词开头的城市太多了。所以使用平均选择性的时候还要考虑分布情况。

创建前缀索引

alert table city_demo add key (city(7));

但mysql无法使用前缀索引做group by和order by。

针对16进制的唯一ID使用索引是常见场景,可考虑长度为8的前缀索引,通常能显著提升性能。

多列索引

不要为每个列都建立索引,可以试图建立组合。mysql在5.0之后提供了一种“索引合并”的策略,一定程度上可以是用表上的多个单列索引定位指定的行,但实际情况更多的说明表上建立索引比较糟糕。

-