mysql buffer pool size 在线调整_缓存

什么是change buffer?

当MySQL要更新一个数据页的时候,如果这个数据页正好在内存中,就直接更新,而如果这个数据页不在内存中的话,在不影响数据一致性的前提下,InnoDB会将这些更新缓存到change buffer中,这样就能减少对磁盘的访问。当下次访问这个数据页的时候,将这个数据页加载到内存,然后执行change buffer中的操作。通过这个流程保证逻辑上的正确性。显然将更新操作缓存到change buffer可以减少磁盘IO,由于是缓存执行速度也有极大提升,而且是读入内存是要占用buffer pool的,所以这种方式还可以节省内存,提高内存的利用率。

merge

change buffer在内存中有拷贝,是可以持久化到磁盘的。将change buffer中的操作应用到源数据得到最新纪录的的过程叫做merge,除了访问这个数据页触发merge之外,后台也有线程定时merge。在数据库正常关闭的情况下也会触发merge。

实用change buffer的条件

对于唯一索引来说,所有的更新操作首先需要验证是否违反唯一性约束,就比如说你要更新一个纪录首先要判断受唯一性约束的这个字段是否在数据库中已经存在了。这个过程是需要将这个数据页加载到内存中的,而如果内存中已经有了这个数据页了,那么就没必要再缓存到change buffer中了,直接在内存中执行操作。

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

插入一条纪录

插入一条数据有两种情况:

1.要更新的数据页在内存中

唯一索引:找到要插入的位置,然后判断是否违反唯一性约束,插入数据。

普通索引:找到要插入的位置,然后插入数据。

两种其实性能相差不大,差别在于唯一索引约束判断需要消耗一点CPU

2.要更新的数据页不在内存中

唯一索引:先将这条纪录所在数据页读入内存,然后判断是否违反唯一性约束,如果没有违反,那么在内存中执行操作。

普通索引:将操作缓存到change buffer,完成。

我们知道,将数据页从磁盘读到内存,是随机IO,这是数据库最大开销之一,

使用场景

change buffer既然这么优秀,那么使用普通索引的所有场景都适用吗?

答案是否定的,change buffer也不是万金油。在触发merge之前,change buffer中积累的操作越多(单个数据页上的更新操作越多),收益就越大。所以只有在更新多而读取少的场景下,使用change buffer性能才能提升。反之,更新或者插入数据后立马就读的这种场景,会频繁触发merge,这种场景,不但没有减少IO次数,反而要增加change buffer的维护成本。这样,change buffer反而成了累赘。

change buffer 和 redo log

  1. 被修改纪录的数据页如果在内存,那么操作就缓存在change buffer
  2. 被修改纪录的数据页如果在内存,那么直接修改内存中的数据

change buffer和2中的修改都是缓存在内存中的,那么如果数据库非正常关闭,掉电宕机的时候,内存中的东西就会丢失,而操作还没有更新到磁盘,问题就严重了。

这个时候就用到redo log。当change buffer每add一条操作,和内存中的数据页每修改一次,都会写一条纪录到redo log,防止操作纪录丢失。

 

总结:

change buffer只能适用于普通索引,在更新操作频繁,读少的场景下,能减少磁盘随机IO的次数,也能节省内存,提高内存利用率。也就是说change buffer能给我们提供唯一索引普通索引选择的依据。