《MySQL实战45讲》学习笔记——索引(二)

普通缩影和唯一索引

普通索引和唯一索引都是二级索引。区别是唯一索引由数据库保证字段的唯一性。

查询过程中,普通索引和唯一索引的性能差不多,普通索引也就是多判断一次而已。

更新过程,普通索引可以使用change buffer优化,唯一索引因为要检查数据的唯一性,必须要将数据读入内存,可能引入磁盘的随机读,性能会下降。

使用普通索引,数据的唯一性要靠业务来保证。

change buffer机制

change buffer 就是一个内存缓存,在更新或者插入数据的时候,如果数据也不在内存中,则先将数据写入change buffer,等以后读数据的时候,将数据也读到内存再进行merge。

在写入操作很频繁的时候,由于无法使用change buffer机制,唯一索引可能成为性能瓶颈。可以通过查看缓存命中率来判断。

但是对于写完立即就读的业务来说,change buffer没什么用途,还增加了维护负担。这时候可以考虑关闭change buffer。

注意区分change buffer 和redo log。redo log 是防止内存中的数据丢失的,change buffer就是那个内存中的数据(之一)。

优化器索引选择
选错索引是MySQL优化器的策略问题。

扫描行数是优化器判断使用哪个索引的指标之一。优化器根据统计量“区分度”来估算扫描函数,但是“区分度”是采样统计的,随着数据的变化,可能变得不准确。但是优化器有纠正机制,就是在更新行数超过1/M的时候重新统计。

扫描函数的统计错误还可能出现在大量的删除或者插入执行事务中,因为为了保证一致性视图,不能及时更新统计数据。

当扫描行数统计不准的时候,可以使用analyze table命令重新统计索引信息。

除了扫描行数,优化器还会考虑一个策略是否需要回表,是否需要排序等。使用explain命令可以查看出优化器选选择的策略的执行预估情况。

如果发现优化器的索引选择不是最好的,可以通过人为的指定force index来优化。或者通过修改SQL语句让优化器选择正确的索引。有些时候可以通过删除或者新建索引来解决。

给字符串加索引
如果字符串很长,给整个字符串加索引存储空间使用的比较多,可以采用前缀索引的方式。前缀索引语法:

mysql> alter table SUser add index index2(email(6));

加前缀索引减小了存储空间,但是付出了查询代价。

  • 因为前缀可能重复,需要扫描更多的行
  • 以前可以使用覆盖索引的查询不能用了

加前缀索引的最佳实践

查看前缀长度对应的区分度。一般来说,前缀超过一定长度,区分度提升就不高了,可以采用95%这样的阈值。

mysql> select 
  count(distinct left(email,4)as L4,
  count(distinct left(email,5)as L5,
  count(distinct left(email,6)as L6,
  count(distinct left(email,7)as L7,
from SUser;

对于有特定结构的字符串,比如身份证,学号等,有不同的策略。

  • 使用倒序存储,这样前缀可以比较短,但是一个比较严重的问题是不能按照区间查询了。

  • 还可以增加一列字段自定义哈希索引,需要范围查询时可以用原字段的索引查询。

  • 针对字段结构进行拆解。取出有区分度的单独做成一列。

你可能感兴趣的:(后端)