普通索引和唯一索引如何选择学习笔记

213 阅读4分钟

查询过程

对于普通索引来说,查找到满足条件的第一个记录后,需要查找下一个记录,直到碰到第一个不满足条件的记录。

对于唯一索引来说,由于索引定义了唯一性,查找到第一个满足条件的记录后,就会停止继续检索。

普通索引会多查几次到不满足为止,但是如果满足数目一定,不会多查询多少次的。因此对性能影响微乎其微

更新过程

change buffer

当需要更新一个数据页时,如果数据页在内存中就直接更新,而如果这个数据页还没有在内存中的话,在不影响数据一致性的前提下,InnoDB 会将这些更新操作缓存在 change buffer 中,这样就不需要从磁盘中读入这个数据页了。在下次查询需要访问这个数据页的时候,将数据页读入内存,然后执行 change buffer 中与这个页有关的操作。通过这种方式就能保证这个数据逻辑的正确性。

同时change buffer在内存中有拷贝,也会被写入到磁盘上。

将change buffer操作应用到原数据页,称为merge,除了访问数据页可以触发,后台线程定期也会merge,数据库正常关闭也会merge。这样可以减少读磁盘,加快语句执行速度,相对于buffer pool(数据页),降低内存占用。

对于唯一索引来说,所有的更新操作都要先判断这个操作是否违反唯一性约束。比如,要插入 (4,400) 这个记录,就要先判断现在表中是否已经存在 k=4 的记录,而这必须要将数据页读入内存才能判断。如果都已经读入到内存了,那直接更新内存会更快,就没必要使用 change buffer 了。

因此只有普通索引使用,随机索引不使用change buffer

因此分为两种情况:

第一种情况是,这个记录要更新的目标页在内存中。这时,InnoDB 的处理流程如下:

对于唯一索引来说,找到 3 和 5 之间的位置,判断到没有冲突,插入这个值,语句执行结束;

对于普通索引来说,找到 3 和 5 之间的位置,插入这个值,语句执行结束。

第二种情况是,这个记录要更新的目标页不在内存中。这时,InnoDB 的处理流程如下:

对于唯一索引来说,需要将数据页读入内存,判断到没有冲突,插入这个值,语句执行结束;

对于普通索引来说,则是将更新记录在 change buffer,语句执行就结束了。

唯一索引肯定会把数据加载到内存中,因为要判断是否有冲突,而普通索引可以不加载到内存中,因此changebuffer可以加速。

change buffer对普通索引更新过程起到加速作用,适用于写多读少的场景,因为每次读会触发merge,导致changebuffer更新进数据中,反而增加维护代价。适用于普通索引,不适用于唯一索引。适用于如账单类,日志类系统。

由于在查询上没有什么差别,建议尽量使用普通索引

如果每次更新后都伴随着对该记录的查询,应当关闭changebuffer,innodb_change_buffer_max_size设置为0

尤其是在使用机械硬盘时,change buffer机制效果显著。

changebuffer和redolog区别 如进行下面操作

insert into t(id,k) values(id1,k1),(id2,k2);

假设k1所在数据库在内存中,k2不在。

  1. Page 1 在内存中,直接更新内存,与changebuffer无关;
  2. Page 2 没有在内存中,就在内存的 change buffer 区域,记录下“我要往 Page 2 插入一行”这个信息
  3. 将上述两个动作记入 redo log 中(图中 3 和 4)。

image.png

当读这两条数据时:

page1在内存中,直接内存返回,WAL之后不用一定读盘,不用将redolog数据更新后才能返回,因此磁盘中内容可以保持原样,redolog也保持不变。

page2不在内存中,需要将page2从磁盘读入,使用changebuffer操作日志,merge后生成正确版本结果返回。并且将merge结果写入磁盘。