数据库索引

在数据库设计中,索引是必不可少的。合理的索引设计可以提升查询的效率。在设计数据库索引的时候需要注意以下几点误区:

很多研发同学评估表数据量不是很大,比如就几千或几万行,如此小表查询不会导致性能问题,因此就不需要添加索引了。

如果数据库就几条这样的并发查询语句,那么大家的想法也没错,但是线上的情况异常复杂,往往评估非常不准确,或对异常情况考虑不足,并发查询量超出预期,业务接口超时报错导致故障。表数据量虽然不多,只有几千或几万行,但大并发下的全面扫描会导致系统CPU资源耗尽,资源争抢导致SQL执行时间变长,进而导致数据库资源池被占满,业务请求因获取连接超时失败而出现了雪崩。

因业务需求的调整,反应到数据库上可能就是一些查询条件的改变,需要对索引进行调整,有的同学选择了先删掉旧索引然后再创建新索引的方式。这种独立拆分方式的索引变更不具备原子性,在旧索引被删除后新索引建立前这期间,如果线上的查询刚好依赖这个旧索引,之前索引扫描的高效查询变成了全表扫描的低效查询,可能导致系统CPU资源耗尽,数据库资源池被占满,进而业务查询超时导致故障。

当 MySQL 中建立的联合索引, 只要索引中的某一列的值为空时(NULL),即便其他的字段完全相同,也不会引起唯一索引冲突,导致唯一约束失效,执行 insert 操作时,即使已经有了该数据,仍然会插入成功。MySQL 官方文档解释只有 BDB 类型的存储引擎支持包含 NULL values 的唯一约束,所以在其他引擎上这种情况发生的时候很容易导致数据冲突。

【最佳实践】
建议无论表的大小,都根据业务查询需求添加合适的索引,避免全表扫描;同时不滥用索引。

选择区分度高的字段建立索引。

多字段and查询时,根据业务查询特点和数据分布评估后需创建联合索引,则需满足最左前缀原则,同时区分度相对高的字段放在联合索引前面。

创建索引,推荐的原则:

  1. 能用单索引,不用联合索引;
  2. 能用窄索引,不用宽索引。
  3. 避免重复建索引,尽量复用已有索引,提高索引使用率。
  4. 尽量使用覆盖索引,无需回表查询,避免随机IO。

满足一定条件后,建议尽量使用前缀索引,用列的前缀代替整个列作为索引key。当前缀长度合适时,可以做到既使得前缀索引的选择性接近全列索引,同时因为索引key变短而减少了索引文件的大小和维护开销。

Join查询中连接字段建立索引,避免全表扫描。

对于范围,<>等非等值查询,只能利用索引的最左列,需要根据实际业务调整规避。

order/group by等语句的字段,适当添加索引可避免排序,如果是多列排序,需要所有列排序方向一致,才能利用索引。
建议给要加唯一索引的属性加一个非空限制或者提供默认值。

索引调整需要仔细评估,特别是删除索引这种会改变 SQL 执行计划的操作,对于索引的重建一定确保drop与add通过一条alter语句执行,删除旧索引并添加新索引,会自动完成转换。对于唯一索引调整,建议删掉唯一键约束但保留索引,做法就是drop唯一索引的同时add一个相同结构的普通索引,且drop和add通过一条alter语句执行,这样确保调整过程中及之后对SQL查询性能无影响。