小米科技|一生挚友redo log、binlog《死磕MySQL系列 二》( 三 )


  • 执行器先到引擎层找到id = 1这一行 , 由于ID是主键 , 所以会在主键索引树找到这一行 。 如果ID=2这一行所在的数据页本来就在内存中 , 就直接返回给执行器 。 否则 , 需要先从磁盘中读入内存 , 然后再返回 。
  • 执行器拿到存储引擎返回id = 2结果后 , 给age加上1 , 原来是25 , 现在就是26在调用引擎接口写入这行新数据 。
  • 引擎将这行数据先更新到内存中 , 同时将这个更新操作记录到redo log中 , 此时redo log处于prepare状态 。 然后告知执行器执行完成了 , 随时可以提交事务 。
  • 接着执行器生成这个操作的binlog , 并把binlog写入磁盘 。
  • 执行器调用引擎的提交事务接口 , 引擎把刚刚写入的redo log改成提交commit状态 , 更新完成 。
到这里你应该就清晰了 , 一条更新SQL会先写redo log再写binlog , 这也就是标题为什么叫一生挚友redo log、binlog

四、为什么需要两阶段提交是为了让redo log跟binlog两份日志之间的逻辑一致 , 看下面俩种情况 。
先写redo log后写binlog
  • 更新语句为age = age +1
  • 将数据写入redo log , MySQL进程异常重启
  • 此时binlog还没有开始写
  • 系统重启后进行数据恢复此时的值为26
  • 需要搭建从库时需要拿binlog进行恢复数据 , 但此时age = age +1 这行的操作是没有记录到binlog的
  • 那么此时的从库就会少这一次的更新 , 恢复出来的age依然是25 , 造成于主库数据不一致 。
先写binlog后写redo log
  • 更新语句为age = age +1
  • 将数据写入binlog , MySQL异常重启
  • 此时redo log 还没写
  • MySQL系统重启 , 这个更新操作是对于redo log是不存在的 , 所以重启后的值依然是25
  • 但binlog 中的值已将是26了
  • 需要搭建从库时 , 从库的值是26 , 主库的值是25 , 造成主从数据不一致
所以说 , 如果不使用两阶段提交 , 那么原库和用它的binlog日志恢复出来的库数据是不一致的 。
五、《孔乙己》让你明白redo log是什么来看一个初中九年级语文课文中《孔乙己》这篇文章 , 就算不记得内容 , 标题总记得哈!
这个案例也是看丁老师文章中提到的 , 为什么丁老可以灵活的使用这个案例来讲redo log而我们想不到呢?
其本质原因是对知识点没有理解透彻 , 使用生活案例来解释技术是让人最容易理解并不难遗忘的 。
《孔乙己》中的主人公就叫他酒店掌柜 , 掌柜的有俩件法宝让比其他老板工作效率高很多 。 一个是小黑板另一个是账本 。
试想一下如果有客人要赊账 , 是直接写到黑板效率高 , 还是翻密密麻麻的账本来的快呢?
掌柜肯定会选择先记录到黑板上 , 等人少或者不忙时再把黑板的记录写到账本中 。
反之老板没有黑板的话 , 只能在密密麻麻的账本中先找到赊账人的名字 , 如果之前有赊账记录追加 , 找了一遍发现没有才进行新增 。
这个过程不仅繁琐而且效率低的让人难以接受 , 如果酒店客人多老板是记录不过来的 。
同样 , 在MySQL中也会存在这个问题 , 每次执行更新语句都需要先找到那条记录 , 然后再更新 , 整个过程IO成本、查找成本都很高 。 所以MySQL也利用了酒店掌柜的智慧使用黑板来提升执行效率 。