索引设计规范
建立索引的目的是:希望通过索引进行数据查找,减少随机IO,增加查询性能 ,索引能过滤出越少的数据,则从磁盘中读入的数据也就越少。
索引是一把双刃剑,可提高查询效率,但也会降低插入和更新的速度并占用磁盘空间。
1. 单张表中索引数量不超过5个
限制每张表上的索引数量,建议单张表索引不超过5个索引;索引可以提高效率同样可以降低效率。索引可以增加查询效率,但同样也会降低插入和更新的效率,甚至有些情况下会降低查询效率。优化器在选择如何优化查询时,会根据统一信息,对每一个可以用到的索引来进行评估,以生成出一个最好的执行计划,如果同时有很多个索引都可以用于查询,会增加MySQL优化器生成执行计划时间,降低查询性能。
2. 禁止给表中的每一列都建立单独的索引
5.6版本之前,一个sql只能使用到一个表中的一个索引,5.6以后,虽然有了合并索引的优化方式,但远没有使用联合索引的查询方式效率高。
3. Innodb表必须要有主键
Innodb是一种索引组织表:数据的存储的逻辑顺序和索引的顺序是相同的。
每个表都可以有多个索引,但是表的存储顺序只能有一种 Innodb是按照主键索引的顺序来组织表的。不要使用更新频繁的列作为主键,不适用多列主键(相当于联合索引) 不要使用UUID、MD5、HASH、字符串列作为主键(无法保证数据的顺序增长)。
主键建议使用自增ID值。
4. 单个索引中的字段数不超过5个
对字符串使用前缀索引,前缀索引长度不超过10个字符;
举例:如有一个CHAR(200)列,在前10个字符内,多数值是惟一的,就可不要对整个列进行索引。对前10个字符进行索引能够节省大量索引空间,也可能会使查询更快。
5. 表主键建议
1) 表必须有主键,不使用更新频繁地列作为主键
2) 尽量不选择字符串列作为主键
3) 不使用UUID、MD5、HASH作为主键
4) 默认使用非空的唯一键
5) 主键建议选择自增或发号器重要的SQL必须被索引:
SELECT、UPDATE、DELETE语句的WHERE条件列ORDER BY、GROUP BY、DISTINCT的字段多表JOIN的字段
6. 区分度最大的字段放在索引前面
7. 核心SQL优先考虑覆盖索引
select的数据列只用从索引中就能够取得,不必读取数据行,换句话说查询列要被所建的索引覆盖。
8. 避免冗余或重复索引
合理创建联合索引(避免冗余),index(a,b,c)相当于index(a)、index(a,b)、index(a,b,c)
1) 索引不是越多越好,按实际需要进行创建,每个额外的索引都要占用额外的磁盘空间,并降低写操作的性能
2) 不在低基数列上建立索引,例如‘性别’
3) 不在索引列进行数学运算和函数运算
9. 尽量避免使用外键约束
1) 不建议使用外键约束(foreign key),但一定要在表与表之间的关联键上建立索引;
2) 外键可用于保证数据的参照完整性,建议在业务端实现;
3) 外键会影响父表和子表的写操作从而降低性能。
10. 不使用%前导的查询,如like“%xxx”,无法使用索引
11. 不使用反向查询,如not in / not like
无法使用索引,导致全表扫描,全表扫描导致bufferpool利用降低;
12. 索引列建议
1) 出现在SELECT、UPDATE、DELETE语句的WHERE从句中的列;
2) 包含在ORDER BY、GROUP BY、DISTINCT中的字段;
3) 多表join的关联列
注意:并不要将符合1和2中的字段的列都建立一个索引,通常将1、2中的字段建立联合索引效果更好
13. 如何选择索引列的顺序
1) 区分度最高的放在联合索引的最左侧(区分度=列中不同值的数量/列的总行数);
2) 尽量把字段长度小的列放在联合索引的最左侧(因为字段长度越小,一页能存储的数据量越大,IO性能也就越好);
3) 使用最频繁的列放到联合索引的左侧(这样可较少的建立一些索引)。
14. 避免建立冗余索引和重复索引
冗余/重复索引会增加查询优化器生成执行计划的时间。
1) 重复索引示例:primary key(id)、index(id)、unique index(id)
2) 冗余索引示例:index(a,b,c)、index(a,b)、index(a)
15. 优先考虑覆盖索引
对于频繁的查询优先考虑使用覆盖索引。
覆盖索引:即包含了所有查询字段(where,select,ordery by,group by包含的字段)的索引,覆盖索引的好处:
1) 避免Innodb表进行索引的二次查询
Innodb是以聚集索引的顺序来存储的,对于Innodb来说,二级索引在叶子节点中所保存的是行的主键信息,如果是用二级索引查询数据,在查找到相应的键值后,还需通过主键进行二次查询才能获取我们真实所需要的数据。
而在覆盖索引中,二级索引的键值中可以获取所有的数据,避免了对主键的二次查询 ,减少了IO操作,提升了查询效率。
2) 可以把随机IO变成顺序IO加快查询效率
由于覆盖索引是按键值的顺序存储的,对于IO密集型的范围查找来说,对比随机从磁盘读取每一行的数据IO要少的多,因此利用覆盖索引在访问时也可以把磁盘的随机读取的IO转变成索引查找的顺序IO。