首页 普通索引和唯一索引,应该怎么选择?
文章
取消

普通索引和唯一索引,应该怎么选择?

查询、更新和插入性能比较

以下面的索引树举例:

查询

执行查询的语句是 select id from T where k=5:

  • 普通索引:从树根一直到叶子节点,查找到满足条件的第一个记录 (5,500) 后,需要查找下一个记录,直到碰到第一个不满足 k=5 条件的记录。
  • 唯一索引:由于索引定义了唯一性,查找到第一个满足条件的记录后,就会停止继续检索。

在查询方面,两者性能差距微乎其微,普通索引只是多了一次判断,而 InnoDB 的数据是按数据页为单位来读写的,两条数据一般同一个数据页,而要多做的那一次“查找和判断下一条记录”的操作,就只需要一次指针寻找和一次计算

更新和插入

对于唯一索引来说,每次在更新/插入时都需要判断数据是否唯一,所以仅仅只是在 change buffer 中记录下操作可不行,必须将对应的数据页读入到内存中进行判断数据是否存在才行。所以唯一索引没有必要使用 change buffer

因此如果在更新和查询操作较多的数据库中使用唯一索引就容易造成系统阻塞。

change buffer 的使用场景

使用原理

当需要更新一个数据页时:

  • 如果数据页在内存中就直接更新
  • 不在内存中,在不影响数据一致性的前提下,InooDB 会将这些更新操作缓存在 change buffer 中,等到下次查询该数据页时执行 change buffer 中与这个页有关的操作。

虽然名字叫作 change buffer,实际上它是可以持久化的数据,在磁盘也保存着它的内容。而将 change buffer 中的操作应用到原数据页,得到最新结果的过程称为 merge。除了访问这个数据页会触发 merge 外,系统有后台线程会定期 merge。在数据库正常关闭(shutdown)的过程中,也会执行 merge 操作。

什么时候被使用

实际上只有在普通索引这种情况下,change buffer 会生效。

change buffer 用的是 buffer pool 里的内存,因此不能无限增大。change buffer 的大小,可以通过参数 innodb_change_buffer_max_size 来动态设置。这个参数设置为 50 的时候,表示 change buffer 的大小最多只能占用 buffer pool 的 50%。

最适合的情况

对于写多读少的业务来说,change buffer 的使用效果最好。多次的写操作都不会马上取读数据页了,对于业务系统来说响应会更快。这种业务系统比如:账单系统、日志类系统。

相反如果写了之后会立马查询,那就没必要使用 change buffer,反而还增加了 change buffer 的维护代价

buffer pool

Buffer Pool 是什么?从字面上看是缓存池的意思。它是 MySQL 当中至关重要的一个组件,可以这么说,MySQL的所有的增删改的操作都是在 Buffer Pool 中执行的。

是否使用唯一索引

  • 如果业务代码保证不会写入重复数据,可以使用普通索引替换唯一索引。
  • 在一些“归档库”的场景,你是可以考虑使用普通索引的。比如,线上数据只需要保留半年,然后历史数据保存在归档库。这时候,归档数据已经是确保没有唯一键冲突了。要提高归档效率,可以考虑把表里面的唯一索引改成普通索引。
本文由作者按照 CC BY 4.0 进行授权

事务到底是隔离的还是不隔离的?

MySQL为什么有时候会选错索引?