几年了,作为一个码农终于把MySQL日记看懂了( 四 )


7.3 ChangeBuffer与Redo log区别Redo log 主要节省的是随机写磁盘的 IO 消耗(转成顺序写) , 而 ChangeBuffer 主要节省的则是随机读磁盘的 IO 消耗 。
这句话怎么理解 , 看下面:
Redo log 与 ChangeBuffer(含磁盘持久化) 这2个机制 , 不同之处在于优化了整个变更流程的不同阶段 。
先不考虑Redo log、ChangeBuffer机制 , 简化抽象一个更新(insert、update、delete)流程:

  1. 从磁盘读取待变更的行所在的数据页 , 读入内存页中
  2. 对内存页中的行 , 执行变更操作
  3. 将变更后的数据页 , 写入至数据磁盘中
其中 , 流程中的步骤1涉及随机读磁盘IO;步骤3涉及随机写磁盘IO;刚好对应ChangeBuffer和Redo log 。
对那句话的理解答案:
  • ChangeBuffer机制 , 优化了步骤1——避免了随机读磁盘IO, 将不在内存中的数据页的操作写入ChangeBuffer中 , 而不是将数据页从磁盘读入内存页中
  • Redo log机制 ,优化了步骤3——避免了随机写磁盘IO , 将随机写磁盘 , 优化为了顺序写磁盘(写Redo log , 确保crash-safe)
7.4 有没有用到ChangeBuffer对于Redo log的区别Redo log机制 , 为了保证crash-safe , 一直都会用到 。有无用到ChangeBuffer机制 , 对于redo log这步的区别在于—— 用到了ChangeBuffer机制时 , 在Redo log中记录的本次变更 , 是记录new change buffer item相关的信息 , 而不是直接的记录物理页的变更(文章中第八节都有体现这一过程) 。在我们mysql innodb中 ,ChangeBuffer机制不是一直会被应用到 , 仅当待操作的数据页当前不在内存中 , 需要先读磁盘加载数据页时 , ChangeBuffer才有用武之地 。
7.5 ChangeBuffer的merge过程
几年了,作为一个码农终于把MySQL日记看懂了文章插图
除了访问这个数据也会触发 merge 外 , 系统有后台线程会定期 merge 。 在数据库正常关闭(shutdown)的过程中 , 也会执行 merge 操作 。
merge过程做三步
  1. 从磁盘读入数据页到内存(老版本的数据页);
  2. 从 change buffer 里找出这个数据页的 change buffer 记录 (可能有多个) , 依次应用 , 得到新版数据页;
  3. 写 redo log 。 这个 redo log 包含了数据的变更和 change buffer 的变更 。
八、日记大连贯U-R-B , 一举攻破拿下前面分别讲的是Binlog、Undo log和Redo log , 下面将他们都串联起来 , 在一些流程体现全部日记 。
同样 , 以一些最经典的更新语句例子展开说明 。
8.1 制造演示数据测试语句:插入语句+查询语句 , a字段是普通索引
insert into ta(a,b) values(2,5),(7, 5)2、select * from t where a in (2, 7)假设原来的数据如下图 , 数据页page1在内存中 , page2不在 。 插入的数据(2 , 5)落在page1 , 数据(7,5)落在page2中 。
几年了,作为一个码农终于把MySQL日记看懂了文章插图
8.2 假设没有日记和ChangeBuffer 示范先不考虑所有日记及ChangeBuffer机制 , 简化抽象一个更新insert流程
  1. 从磁盘读取待变更的行所在的数据页 , 读入内存页中
  2. 对内存页中的行 , 执行变更操作
  3. 将变更后的数据页 , 写入至数据磁盘中

几年了,作为一个码农终于把MySQL日记看懂了文章插图
8.3 考虑所有日记和ChangeBuffer 示范--现有Innodb流程过程是 两阶段提交-----日记刷盘------数据刷盘(涉及Redo log lsn 和 ChangeBuffer的内容)
8.3.1 两阶段提交过程
  1. 数据(2,5)所在页page1在内存中直接更新内存;数据(7,5)所在页page2不在内存中 , 记录change buffer(具有唯一性的索引或者没有使用change buffer的操作是将磁盘中的数据页读入内存中并做更新) 。
  2. 写undo日记 。 先写缓存 , 后面根据刷盘参数决定何时刷入磁盘 , 后面的redo/Binlog都一样 。 日记刷盘 在每一个日记中基本已经提到 , 它和设置的参数有关 , 具体刷盘可以参考上文4.3和6.5章节 , 下文不会再展开介绍 。
  3. 写redo日记(先记在内存中的更新 , 然后记录在内存中的change buffer的改变)
  4. 日记状态改成prepare阶段 。
  5. 写Binlog日记 。
  6. 提交事务 , 日记状态改成commit阶段 。

几年了,作为一个码农终于把MySQL日记看懂了文章插图
8.3.2 merge 过程紧接着上文 , 图片可上下参考 , 假设现在执行查询语句 “select * from t where a in (2, 7)”, 此次查询索引a=7所在的数据页不在内存中 , 并且上一步更新已经在change buffer中有记录 , 将会触发merge过程(参考第七章节7.5) 。