二、Change Buffer(更改缓存 或 写缓存)

1)概念

Change Buffer(更改缓存区),是buffer pool中的一块内存区域

image-20220820142608461

2)引入目的

是MySQL对二级索引(或普通索引)的写操作所做的优化。
如果要进行写操作的数据不在 buffer pool中,那么就会将写操作记录到 change buffer

3)Merge 操作

当数据页中的某条数据记录被DML语句(INSERTUPDATEDELETE )操作更改后,立马被其他会话读取了,此时会从磁盘重新读取这个数据所在的数据页
在将这个数据页读进 buffer pool中之前,会先触发 change buffer的merge操作,也就是将change buffer中的数据页中更改的数据与原数据页中的数据进行合并 。
和聚集索引不一样的是,二级索引通常不是唯一的,而且数据插入到二级索引中的顺序是随机的

何时执行:

  • 目标数据页加载到 buffer pool 中时,会先执行 change buffer 的 merge操作
  • 系统后台会定期执行change buffer 的 merge操作
  • MySQL服务正常关闭或重启时,也会触发 change buffer 的 merge操作

执行说明:

  • 当有许多受影响的行和待更新的二级索引时,change buffer的合并操作可能会花费数小时。
    在这段时间内,磁盘I/O的迅速增加可能导致某个重要的磁盘查询操作速度变慢。
  • change buffer 的合并操作可能会持续到某个事务提交后,或当MySQL服务器关闭或重启时。

4)Purge 操作

作用:将更新的索引数据页写入磁盘。
清除操作将一系列的索引值写入磁盘块比将每个值实时写入磁盘更高效

何时执行:

  • MySQL认为系统处于"空闲"的时候

    会自动触发 purge 操作,此时不会产生性能问题

  • MySQL在正常关闭时

    MySQL 会把内存的脏页都 flush 到磁盘上,这样下次 MySQL启动的时候,就可以直接从磁盘上读数据,启动速度会很快。

    此时不会产生性能问题

  • 内存不够用了,会先将脏页写到磁盘

    buffer pool中的数据页有三种状态: 第一是,还没有使用的;第二是,使用了并且是干净页;第三是,使用了并且是脏页

    对于第三种数据页,MySQL会将脏页数据刷新到磁盘上

  • redo log 写满了,要 flush 脏页

    这种情况是 InnoDB 要尽量避免的。
    因为出现这种情况的时候,整个系统就不能再接受更新了,所有的更新都必须堵住

5)存储分析

  • 在内存中,change buffer占用了 buffer pool 的一部分内存空间。
  • 在磁盘上,change buffer是也是系统表空间(system tablespace)一部分
    在系统表空间中,当数据库服务器被关闭后,对二级索引所做的变化会写入系统表空间中。

也就是说,change buffer 不仅可以将数据页保存在内存中,也会将数据持久化到磁盘中的系统表空间中

6)配置(Configuring the Change Buffer)

当对某张表执行 INSERTUPDATEDELETE操作的时候,被索引列的值通常是未排序的,需要大量 I/O 才能使二级索引保持最新。
当相关的数据页不在 buffer pool 中时,对二级索引entry所做的更改会被缓存到 change buffer 中,因此不需要立即从磁盘中立即读取数据页,从而避免了额外的I/O操作。当数据页被加载到 buffer pool 时,缓存的变化会被合并,已更新的数据页稍后会被写入磁盘中。当MySQL服务器空闲的时候或者正准备关闭的时候,InnoDB主线程会对缓存的变化进行合并。

对于I/O密集型的工作负载,改变缓存由于会引起更少的磁盘读写而更有价值。比如说:对于有大量 DML操作(比如:批量插入)的应用程序

但是,change buffer 由于占用了 buffer pool 中的部分内存空间,而使得缓存数据页的内存空间变少。
如果工作集几乎适合缓冲池,或者您的表的二级索引相对较少,最好禁用 change buffer
如果工作数据集完全适合缓冲池,更改缓冲不会带来额外的开销,因为 change buffer 只适用于不在 buffer pool 中的数据页

缓存类型配置

配置方式:设置 innodb_change_buffering 变量
作用:控制着 InnoDB 执行更改缓冲的程度
默认值:all

可选值 说明
all(默认) 默认值,对 插入操作、标记删除操作和清除操作进行缓存
none 不缓存任何操作
inserts 只缓存插入操作
deletes 只缓存被标记为删除的操作
changes 只缓存插入操作与被标记为删除操作
purges 只缓存在后端发生的物理删除操作
缓存最大百分比配置

配置方式:设置 innodb_change_buffer_max_size 变量
配置作用:调整 change bufferbuffer pool 中的内存占比(百分比的形式)
默认大小:25,最大值是50
查看方式:show variable like 'innodb_change_buffer_max_size';
说明:

  • INSERTUPDATEDELETE操作很多时,考虑将这个值调大

    因为,change buffer 合并记录的速度 跟不上 新change buffer记录增长的速度,而导致 change buffer 很快就到达内存上限

  • 当和用于报告的静态数据一起使用时 或者 change buffer消耗了 buffer pool中的大部分内存,考虑将这个值调小

    因为这会导致 buffer pool 中的页面的老化速度加快

  • 可以动态更改这个变量的值,而不需要重启服务器

7)使用场景

适用场景
  • 数据库中大部分是非唯一索引的情况下
  • 写入操作较多且读取操作较少的情况下
  • 写入数据后不需要立即读取的情况下
不适用场景
  • 二级索引包含降序索引列

  • 主键包含降序索引列

8)监控(Monitoring the Change Buffer)

主要有下面4种方式:

  • 使用 InnoDB标准监控输出(InnoDB Standard Monitor output)

  • 查询 INFORMATION_SCHEMA.INNODB_METRICS

    mysql> SELECT NAME, COMMENT FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME LIKE '%ibuf%'\G;
    
  • 查询 INFORMATION_SCHEMA.INNODB_BUFFER_PAGE

    mysql> SELECT (SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_BUFFER_PAGE WHERE PAGE_TYPE LIKE 'IBUF%') AS change_buffer_pages,
    (SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_BUFFER_PAGE) AS total_pages,
    (SELECT ((change_buffer_pages/total_pages)*100)) AS change_buffer_page_percentage;
    
    +---------------------+-------------+-------------------------------+
    | change_buffer_pages | total_pages | change_buffer_page_percentage |
    +---------------------+-------------+-------------------------------+
    |                   2 |        8192 |                        0.0244 |
    +---------------------+-------------+-------------------------------+
    1 row in set (0.03 sec)
    
  • Performance Schema

    为高级的性能监控提供了 change buffer 互斥等待工具

    mysql> SELECT * FROM performance_schema.setup_instruments
    WHERE NAME LIKE '%wait/synch/mutex/innodb/ibuf%';
    

参考资料

名称 参考链接 参考书籍
change buffer 引入目的 https://blog.csdn.net/shaofei_huai/article/details/119801354
change buffer merge 操作 https://www.homedt.net/399194.html
change buffer purge 操作 https://www.cnblogs.com/xibuhaohao/p/10772767.html
change buffer 适用场景 https://cloud.tencent.com/developer/article/1596673