Mysql InnoDB Redo log

一丶什么是redoinnodb是以也为单位来管理存储空间的,增删改查的本质都是在访问页面,在innodb真正访问页面之前,需要将其加载到内存中的buffer pool中之后才可以访问,但是在聊事务的时候,事务具备持久性,如果只在内存中修改了页面 , 而在事务提交后发生了系统崩溃,导致内存数据丢失,就会发生提交事务所作的更改还没来得及持久化到磁盘 。
那么如何保证到提交的事务 , 所作更改一定持久化到磁盘了昵?
最简单粗暴的固然是 , 每次事务提交都将其所作更改持久化到磁盘 。这种操作又存在如下问题:

  • 刷新一个完整的页面,十分浪费IO,有时候事务所作的更改只是一个小小的字节,但由于innodb是以页为单位的对磁盘进行io操作的,这时候需要把一个完整的页刷新到磁盘,为了一个字节刷新16k的内容,是不划算的
  • 随机io刷新缓慢,一个事务包含多个数据库操作 , 一个数据库操作包含对多个页面的修改,比如修改的数据不在相邻的页,存在多个不同的索引B+树需要维护,这时候需要刷新这些零散的页面,进行大量的随机IO
InnoDB是如何实现事务提交的持久化——记录下更改的内容
在事务提交的时候只记录下,事务做了什么变更到redolog,中这样即使系统崩溃了,重启之后只需要按照redo log上的内容进行恢复,重新更新数据页 , 那么该事务还是具备持久性的,这便是重做日志——redo log 。使用redo log的好处:
  • redo log占用空间?。涸诖娲⑹挛袼鞅涓氖焙?nbsp;, 需要存储变更数据页所在的表空间,页号 , 偏移量以及需要更新的值时,需要的空间很少 。
  • redo log是顺序写入磁盘的,在执行事务的过程中,在执行每一条语句的时候,就可能产生若干条redo log,这些日志都是按照产生的顺序写入磁盘的,也就是使用顺序io
二丶redo log 日志的格式
Mysql InnoDB Redo log

文章插图
  • type:redo log日志的类型
  • space id:表空间号
  • page number:页号
  • data:日志内容
通常一个执行语句是会修改到许多页面的 , 比如一个表具备多个索引,进行更新的时候需要维护聚簇索引和各种非聚簇索引,表中存在多少个索引就会可能会更新到多少个B+树,针对一颗B+树来说,极可能更新到叶子节点,也可能更新到非叶子节点,甚至还伴随着创建新页面,页面分裂,在内节点页面添加目录项等等操作 。
理论上说red log只需要记录下insert 语句对页面所有的修改即可,但是插入数据到一个页面,也伴随着对这个页面的File Header,Pahe Header等等信息的修改
Mysql InnoDB Redo log

文章插图
可见,将一条记录插入到一个页面 , 需要更改的地方很多,为此redo log定义了许多不同的日志格式,从物理层面来说:redo log指明了需要在哪一个表空间,的哪一个页进行什么修改内容,从逻辑层面来说:redo log在mysql崩溃恢复后,并不能直接使用这些日志记录的内容,而是需要调用一些函数,将页面进行恢复
三丶Mini-Transactionmysql把底层页面的一次原子访问过程称为一个Mini-Transaction(MTR)(比如向B+树中插入一条记录的过程算作一个MTR,即使这个sql涉及到多个B+树)一个MTR可以包含一组redo log , 在进行崩溃恢复的时候需要把这一组MTR看作是一个不可分割的整体(B+树中插入一条记录,可能涉及到叶子节点,非叶子点的改动,不能说只新增了叶子节点 , 但是没用更新非叶子节点,需要保证这个过程的原子性)
一个事务可以包含多个语句 , 一个语句可以包含多个MTR,一个MTR可以包含多个redo log日志 , 那么innodb是如何确认多个redo log属于一个MTR的昵
Mysql InnoDB Redo log

文章插图
多个redo log以最后一条类型为MLOG_MULTI_REC_END类型的日志结尾,那么视为前面的redo log为同一MTR中的日志 。系统在进行崩溃恢复的时候,只有解析到MLOG_MULTI_REC_END类型的日志的时候,才认为解析到了一组完整的redo log日志,才会进行恢复 。
有些需要保证原子性的操作,只会产生一条redo log,比如更新Max Row ID(innodb在用户没用指定主键的时候,将此值存储在页中,没增大到256的整数倍的时候,才会更新写回磁盘),这个时候会将其的type字段的第一个比特置为1,表示这个单个redo log 便是一个原子性操作,而不是加上一个

推荐阅读