mysql中的change_MySQL中的change buffer

参考:

https://blog.csdn.net/weixin_38304221/article/details/88635432

https://blog.csdn.net/nanjingitany/article/details/102856472

https://www.cnblogs.com/abclife/p/7625281.html

https://www.cnblogs.com/ging/p/13467833.html

MySQL中的change buffer

MySQL的一条语句,大致流程查看内存→读取磁盘数据页→返回数据。

当比如查找一个 a=5的记录的时候,并不是只查找出这一条数据,它所在的整个数据页都会查找出来(每个数据页16KB)。

下次查找a=6的记录的时候,发现该页已经在内存中了,直接返回,不需要磁盘IO。

但是当时增、删、改操作时,并不会每一次操作都进行一次磁盘IO,使用change buffer可以降低磁盘随机IO。

change buffer首先是可持久化的数据。

当更新某个数据页时,该页在内存中,那么直接更新。

如果该页不在内存中,那么先将更新操作记录在change buffer中,这时不需要从磁盘中读出数据页。

将操作记录到redo log中,防止机器意外关闭导致数据丢失。

这时已经可以返回给客户端更新成功了,因为即使机器意外重启,也可以通过redo log找回数据。

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

什么时候将change buffer中的数据更新到磁盘中?

当下一次查询命中这个数据页的时候,会先从磁盘中读取数据页到内存中,然后先执行change buffer的merge操作,保证数据逻辑的正确性。除了查询操作外,系统有后台线程会定期merge,数据库正常关闭(shutdown)的时候,也会进行merge操作。

change buffer 和 redo log 对于磁盘的随机IO影响。

redo log是减少 随机写磁盘IO 的消耗。每个操作先记录redo log,系统空闲时或redo log满时进行磁盘IO。

change buffer是减少 随机读磁盘IO 的消耗。更新时如果内存中不存在该数据页,也不需要马上进行磁盘IO,而是先记录在change buffer中,等待时机统一merge。

所以根据业务场景选择是否使用change buffer。

当写少读多的情况下:change buffer的利用率不高,因为可能刚一更新完可能就触发merge操作,change buffer没有起到减少随机IO,还多了一个维护change buffer的成本。

当写多读少的情况下:change buffer的提升效果较明显,可能很多条更新后,也没有一个查询线程来触发merge操作,可以大幅减少磁盘的随机IO。

唯一索引和 普通索引(在业务逻辑层保证数据唯一)的选择

命中唯一索引和普通索引时MySQL筛选数据的逻辑不同。

比如一个查询语句 select * from table where k=5;先通过B+树从树根开始,按层搜索到叶子节点,也就是数据页。

唯一索引 k:由于索引定义了唯一性,所以在数据页中找到第一个满足条件的记录后,直接返回。

普通索引 k:没有定义索引的唯一性,所以在查找到第一条满足k=5后,还会继续遍历下一条,直到查到的k != 5的时候,结束遍历。

那么两种索引的效率差距有多大呢?

其实是很小,几乎可忽略。普通索引相对于唯一索引多的一步操作就是"查找并判断下一条记录",因为都存在于同一个数据页,所以内存遍历对于CPU的开销可忽略。一个数据页可以存在上千个key,刚好下一条数据在下一个数据页而触发再次读取数据页的概率很低。所以这两种索引的效率几乎一样。

但是当进行增删改操作时,两种索引的效率就有明显的差距了。

因为唯一索引每个插入或者更新都要判断是否违反唯一约束,所以每次更新都要从内存中找到这个记录对应的数据页,没有的话需要从磁盘中读出,反正都要从磁盘读数据页了,还不如直接更新内存/磁盘,那么也就意味着change buffer失去意义,所以唯一索引使用change buffer 的话反倒会降低效率,所以只有普通索引能使用到change buffer。

浅谈mysql的change buffer

1.数据的更新过程

当mysql执行更新操作时,需要先更新一个数据页。如果这个数据页在内存中,则会直接更新,如果

这个数据页不在内存中,InnoDB会将这个更新操作缓存在change buffer中,当下次需要查询访问这个数据页的时候,会将数据页读入内存,然后执行change buffer中和这个数据页相关的操作,这样就保证了数据的逻辑正确性。

2.merge触发

将change buffer中的操作应用到原数据页,得到最新结果的过程称为merge。除了访问这个数据页会触发merge外,系统有后台线程会定期merge。在数据库正常关闭(shutdown)的过程中,也会执行merge操作。

3.使用change buffer的场景

只有普通索引的更新会使用change buffer,用来提高内存利用率,但是如果被更新的字段是唯一索引,就不会使用change buffer,因为更新操作会判断是否违反唯一约束的条件,必须将数据页读入内存才能判断,因此唯一索引不会使用change buffer,只有普通索引才能使用。

在日常业务场景中,对于写多读少的操作,使用change buffer的效果最好,例如账单类、日志类的操作,如果是读写操作都是很多的情况下,写完后将操作记录保存在change buffer中然后立即查询,这样会频繁触发merge,增加了IO的操作频率,这种场景使用change buffer并不能带来性能的提升,这种业务场景应该关闭change buffer。

4.change buffer的大小设置

在InnoDB中,可以通过参数innodb_change_buffer_max_size来设置,默认值是25,最大是50。例如当这个参数值是50 的时候,表示change buffer最多只能占用buffer pool的50%

5.索引的选择

唯一索引和普通索引在查询上并无区别,但是在更新操作上两者对性能的影响是不一样的,所以建议尽量使用普通索引。

Change Buffer的处理过程

对非唯一的普通索引的新增或更新操作,如果索引B+树的需要新增或更新的数据页不在内存中,则直接更新change buffer,等到后面需要使用这个数据页(真正读到内存中来)的时候,再根据change buffer在内存中做merge合并操作。

Change Buffer有什么好处?

先想想没有change buffer时候,在缓冲池中没有对应数据页时会怎么更新。概括来说,有两个步骤:

首先需要从磁盘中读取对应的数据页到内存中

然后更新内存中的数据页。

首先分析主键索引或者非主键索引中的唯一索引,插入或者更新的操作。

主键如果是自增的,只需要读取顺序读取磁盘中的页,然后插入最新的行即可。主键如果是非自增的或者是自己设置的值,那么可能需要做一次随机磁盘IO操作,读取到对应的页,做一下唯一性判断,然后插入数据即可。

针对非主键索引中的唯一索引,大概率需要做随机磁盘IO读取,然后判断唯一性,再插入对应的行。

所以对于主键索引和非主键的唯一索引,因为有唯一性判断,所以更新操作时,必须要从磁盘中读取数据页,判断唯一性,然后才能确定这个更新操作是否成功,即这个磁盘的IO操作是不可避免的。

对于非唯一索引来说,其实步骤也是类似的。但是因为不需要做唯一性判断,所以为了提高更新的性能,Mysql给出的解决方案就是使用change buffer来保存对非唯一索引的更新。也就是说,当需要更新非唯一索引时,直接操作change buffer,成功即可返回。

那么什么时候会真正更新数据页呢?有两种情况会触发:

被动:在后续的真正需要读这个非唯一索引时,把索引的数据页从磁盘读取到内存中,再通过change buffer做一个merge操作,merge操作以后,内存中的数据页就是最新的了。

主动:innoDB引擎中有线程会主动的定期做merge操作

业务实践

利用普通索引的change buffer特性,当业务场景中的写远大于读时,常见场景为日志表,当某些列必须建立索引时,可以考虑建立普通索引,提高写入性能。

如果业务场景的写之后立即伴随读,如果列的值是唯一的

那么其实建立普通索引是不合适的,因为写的过程,虽然利用了change buffer暂时提高了写的性能,但是在读的时候还是需要磁盘IO。可以考虑建立唯一索引,在索引写的时候,就提前读取数据到缓冲池中,提高读的性能。

change buffer是一种特殊的数据结构,当要修改的辅助索引页不在buffer pool中时,用来cache对辅助索引页的修改。对辅助索引页的操作可能是insert、update和delete操作。等到相关的索引页被读入buffer pool中后,才会使用change buffer中的内容对辅助索引页进行修改(即merge操作)。

和聚集索引不同,辅助索引通常是不唯一的,插入辅助索引通常也是随机的。同样,对辅助索引的删除、更新也通常是不连续的。

等到相关的索引页被读入buffer pool中后,才会使用change buffer中的内容对辅助索引页进行修改(即merge操作)可以避免大量的磁盘随机访问I/O。

间歇性的,在系统空闲或关闭过程中,会执行purge操作,将新的索引页写入磁盘。purge操作一次写多个索引值会比每次修改后就立即写入磁盘的效率高。

对change buffer的merge可能需要好几个小时,如果被更新的辅助索引行比较多。在merge过程中,磁盘的I/O会增加,可能会引起其他查询的性能的降低。

merge操作也可能发生在事务提交后。事实上,即使在实例重启后,还会可能发生merge操作。

在内存中,change buffer会占用buffer pool的空间;在物理磁盘上,change buffer是system tablespace的一部分,所以对索引的修改在数据库重启后仍然存在change buffer中。

change buffer包含的特性也叫作change buffering,包含insert buffering、delete buffering、purge buffering。

change buffer中数据类型和总量由参数innodb_change_buffering和innodb_chagne_buffer_max_size配置。查看change buffer中数据的信息,可以通过show engine innodb status查看。

change buffer在老版本中被称作insert buffer。

1.监控change buffer

2.查看information_schema

information_schema.innodb_metrics提供了change buffer的统计信息名称和说明:

information_schema.innodb_buffer_page提供了buffer pool中每个页的元数据,包含change buffer 索引页和change buffer位图页。

change buffer页中page_type.ibuf_index表示change buffer索引页;page_type.ibuf_bitmap表示change buffer位图页。

提醒:查看innodb_buffer_page会有很大的性能开销。最好是在空闲时间或测试环境执行。

比如,可以查看change buffer的索引页和位图页占据buffer pool的比例:

performance_schema还为高级性能监控提供了change buffer mutex的等待指令:

3.配置change buffer

可以通过参数innodb_change_buffering来控制是否启用change buffer。

从5.6.2开始,参数innodb_change_buffer_max_size设置了change buffer可以占用buffer pool的百分比,默认是25,最大可以设置为50。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值