redo log
想要保证
一致性最简单的做法是在每次事务提交的时候,将该事务涉及修改的数据页全部刷新到磁盘中。但是这么做会有严重的性能问题。
Innodb
是以页
为单位进行磁盘交互的,而一个事务很可能只修改一个数据页里面的几个字节,这个时候将完整的数据页刷到磁盘的话,太浪费资源了。一个事务可能涉及修改多个数据页,并且这些数据页在物理上并不连续,使用随机IO写入性能太差。
redo log
只记录事务对数据页做了哪些修改,这样就能完美地解决性能问题了(相对而言文件更小并且是顺序IO)。
redo log
用来恢复提交后的物理数据页(恢复数据页,且只能恢复到最后一次提交的位置)。
redo log组成
redo log由
内存中的日志缓冲(redo log buffer
)和磁盘上的日志文件(redo logfile
)组成的。
mysql
每执行一条 DML
语句,先将记录写入redo log buffer
,后续某个时间点再一次性将多个操作记录写到redo log file
。
这种 先写日志,再写磁盘 的技术叫做WAL(Write-Ahead Logging)
技术。
在计算机操作系统中,用户空间(user space
)下的缓冲区数据一般情况下是无法直接写入磁盘的,中间必须经过操作系统内核空间(kernel space
)缓冲区(OS Buffer
)。redo log buffer
写入 redo logfile
实际上是先写入 OS Buffer
,然后再通过系统调用 fsync()
将其刷到 redo log file。
redo log
实际上记录数据页的变更,而这种变更记录是没必要全部保存,因此redo log
实现上采用了大小固定,循环写入的方式,当写到结尾时,会回到开头循环写日志。
undo log
undo log
主要记录了数据的逻辑变化,undo log有两个作用:提供回滚和多个行版本控制(MVCC)。
在数据修改的时候,不仅记录了redo,还记录了相对应的undo,如果因为某些原因导致事务失败或回滚了,可以借助该undo进行回滚。
undo log和redo log记录物理日志不一样,它是逻辑日志。当delete一条记录时,undo log中会记录一条对应的insert记录,反之亦然,当update一条记录时,它记录一条对应相反的update记录。
当执行rollback时,就可以从undo log中的逻辑记录读取到相应的内容并进行回滚。有时候应用到行版本控制的时候,也是通过undo log来实现的。当读取的某一行被其他事务锁定时,它可以从undo log中分析出该行记录以前的数据是什么,从而提供该行版本信息,让用户实现非锁定一致性读取。
undo log删除
当事务提交的时候,innodb不会立即删除undo log,因为后续还可能会用到undo log。隔离级别为repeatable read时,事务读取的都是开启事务时的最新提交行版本,只要该事务不结束,该行版本就不能删除,即undo log不能删除。
但是在事务提交的时候,会将该事务对应的undo log放入到删除列表中,未来通过purge来删除。并且提交事务时,还会判断undo log分配的页是否可以重用,如果可以重用,则会分配给后面来的事务,避免为每个独立的事务分配独立的undo log页而浪费存储空间和性能。