一,查询和更新上的区别

这两类索引在查询能力上没有差别,主要考虑的是对更新性能的影响。建议尽量选择普通索引。

1.1 MySQL 的查询操作

  • 普通索引:查找到第一个满足条件的记录后,继续向后遍历,直到第一个不满足条件的记录
  • 唯一索引:由于索引定义了唯一性,查找到第一个满足条件的记录后,直接停止继续检索

普通索引会多检索一次,几乎没有影响。因为 InnoDB 的数据是按照数据页为单位进行读写的,需要读取数据时,并不直接从磁盘读取记录,而是先把数据页读取到内存,再去数据页中检索。 一个数据页默认是 16KB,对于整型字段,一个数据页可以存放近千个 key,除非要读取在数据在数据页的最后一条记录,就需要在读取一个数据页,这样的情况很少,对 CPU 的消耗基本可以忽略不计。因此说,在查询数据方面,普通索引和唯一索引没有差别。

1.2 MySQL的更新操作

更新操作并不是直接对磁盘中的数据进行更新,是先把数据页从磁盘读取到内存,再更新数据页

  • 普通索引:将数据页从磁盘读入到内存,更新数据页
  • 唯一索引:将数据页从磁盘读入到内存,判断是否唯一,在更新数据页

由于 MySQL 中有个 change buffer 机制,会导致普通索引和唯一索引在更新上有一定的区别。 change buffer 的作用是为了降低 IO 操作,避免系统负载过高。 change buffer 将数据写入数据页的过程,叫做 merge。

如果需要更新的数据页在内存中,会直接更新数据页,如果数据不在内存中,会将更新操作记入 change buffer,当下一次读取数据页时,顺带 merge 到数据页中, change buffer 页有定期的 merge 策略。数据库正常关闭的过程中,也会触发 merge。

对于唯一索引,更新前需要判断数据是否唯一(不能和表中数据重复),如果数据页在内存中,就可以直接判断并且更新,如果不在内存中,就需要去磁盘中读出来,判断是否唯一,是的话就更新。change buffer 是用不到的,即使数据页不在内存中,还是要读出来。 change buffer 用的是 buffer pool 里的内存,因此不能无限增大。change buffer 的大小,可以通过参数 innodb_change_buffer_max_size 来动态设置,这个参数设置为 50 的时候,表示 change buffer 的大小最多只能占用 buffer pool 的 50%。

结论:

只有普通索引用到 change buffer,唯一索引用不到 change buffer