MySql索引大总结

0、索引分类

在这里插入图片描述

1、不应该创建索引的场景

  • 1、Where子句里用不到的字段
  • 2、表的记录非常少
  • 3、表中有大量重复数据,列选择性很低,例如性别字段(只能是男、女),索引的选择性越高,查询效率越好,使用索引就能过滤更多的行

2、应该创建索引的原则场景

  • 1、select语句中频繁作为where查询条件的字段
  • 2、update/delete语句中作为数据选择的字段
  • 3、需要group by 、order by 出现的字段
  • 4、distinct所使用的字段
  • 5、字段的值有唯一性约束
  • 6、对于边表查询,联接字段应该创建索引,且类型应该保持一致,避免发生列的类型隐式转换,致索引失效

3、可能导致索引失效的场景

例如 我们有一张user表,里面有一个字段是name ,我们对name创建了一个普通的BTree索引

  • 1、列是表达式的一部分,左边的列参与了表达式/函数的计算
 select * from user where length(name) > 10;
  • 2、使用了左模糊查询,查询名字以“大”结尾的用户
 select * from user where name like '%大';
  • 3、使用OR查询的部分字段没有索引,first_name有索引,而last_name没有索引
 select * from employee where first_name='qiao' or last_name='li';
  • 4、存在隐式类型转换,dept_no列是字符串类型,查询条件会存在隐式类型转换
 select * employee from where dept_no = 3;
  • 5、联合索引不满足最左前缀查询,存在一个联合索引 index(first_name,last_name)
 select * employee from where last_name= 'li';
  • 6、索引字段建议添加非空约束,这也是MySQL官方推荐的
 select * employee from where first_name is null;

4、索引的优化

4.1、长索引字段的优化

  例如 employee表中的first_name字段经常存储一个大的字符串,几百个字符,新疆人的名字就非常     长,这个时候如果对first_name直接建立索引,则效率不高,因为单条索引数据比较大的话,则每次查询需要访问的索引块就比较多,磁盘IO就多,最终效率不高。
  ==方案一==:一个比较好的解决方案是,增加一个冗余字段first_name_crc32用来存储first_name的hash值,利用crc32算法,并对first_name_crc32创建普通索引。

优化之前:

 select * from  employee where first_name = '这是一个很长的字符串,可能有几百个字符';

优化之后:

 select * from employee  where first_name_crc32 = 
        crc32( '这是一个很长的字符串,可能有几百个字符') and first_name = 
        '这是一个很长的字符串,可能有几百个字符';

方案二:直接创建前缀索引,只取列前多少个字符建立索引。问题的关键是取多少字符合适,这里有一个方法叫做“逐步递增尝试”法。但是前缀索引有一定的局限性,无法应用于order by 、group by 与覆盖索引。
第一步:先计算该列的选择性值:

select count(distinct first_name)/count(*) from employees   ;

得到选择性大小为:0.0042
!
第二步:尝试取前3、5、6、8得到各选择性大小:

-- 0.0022
select count(distinct lef

 1. List item

t(first_name,3))/count(*) from employees   ;
-- 0.0038
select count(distinct left(first_name,5))/count(*) from employees   ;
-- 0.0041 
select count(distinct left(first_name,6))/count(*) from employees   ;
-- 0.0042 这个值最接近0.0042,所以可以取前8个字符作为前缀索引
select count(distinct left(first_name,8))/count(*) from employees   ;

当前缀索引长度为8时,可以让选择性最高,同时索引数据结构占用存储空间最小,
第三步:利用第二步确定的前缀大小创建前缀索引

alter table employees add index(first_name(8))

4.2、优化索引合并index_merge

employees 表有2个单列索引 index (first_name)与index (last_name )

select * from employees  where first_name ='qiao' and last_name = 'li' ;

使用explain 分析这个sql会发现type=index_merge索引合并,索引合并一般是不推荐的,
可以创建一个联合索引index (first_name,last_name)这样再进行explain分析,会得到type=ref,
而ref性能是优于index_merge的

  • 3、优先使用覆盖索引covering_index
    如果使用了覆盖索引则,explain中的extra=using index ,例如存在联合索引
    index (first_name,last_name)
    优化之前:
 select * from employee  where first_name ='qiao' and last_name = 'li' ;

优化之后:

  select first_name ,last_name from employee  where first_name ='qiao' and last_name = 'li';

如果我们只需要返回first_name 与 last_name 两列,就可以使用covering_index覆盖索引,
为什么覆盖索引性能比没有使用覆盖索引性能好?
因为在没有使用覆盖索引的情况下,正常的索引访问是,先访问一个普通索引树获取对应的主键集合,然后去访问主键索引(聚集索引)获取数据行。但是如果需要返回的列就在普通索引树中,就不需要再去访问主键索引(聚集索引),只需要访问一次索引树就行了,所以性能就好一些。

4.3、重复索引、冗余索引、未使用的索引

   因为对于数据行的insert、update、delete是有索引开销的,所以对于重复索引、冗余索引与未使用的索引建议删除,日后需要的时候,再按需创建。

猜你喜欢

转载自blog.csdn.net/s2008100262/article/details/111434868