InnoDB Undo日志什么时候会被删除?

Undo日志在事务执行过程中生成,既服务于自己,也服务于其它事务。 生成Undo日志的事务提交之后,Undo日志服务于自己的使命就结束了。 Undo日志服务的其它所有事务都提交之后,它服务于其它事务的使命就结束了,同时它的整个使命也就结束了。 本文接下来会简单介绍下Undo日志的作用,然后详细聊聊Undo日志的删除的具体时机。

Undo日志的作用

用于事务回滚

在事务的执行过程中,如果执行了插入、删除、修改语句,会生成相应的Undo日志,用于在事务回滚时把数据恢复到事务执行之前的状态,以实现事务的一致性。

用于MVCC

Multi Version Concurrency Control,缩写MVCC,多版本并发控制,在Read Commited、Repeatable Read隔离级别下,以不加锁的方式解决了脏读、不可重复读,以及部分的解决了幻读的问题。

Undo日志中保存了行数据的多个版本,数据的多个版本按照时间由近到远形成了一个版本链,在Read Commited、Repeatable Read隔离级别下,当某个事务的Select语句读取到其它事务修改过但未提交的行时,未提交的数据对该Select语句是不可见的,Select语句会去Undo日志的版本链中寻找其可见的版本。

Undo日志的删除

Undo日志的删除是异步的,在它的使命结束之后,会由Purge线程删除。

用于事务回滚

在Read Uncommited、Serializable隔离级别下,Undo日志中用于事务回滚,而不需要服务于MVCC,所以在生成Undo日志的事务提交之后,Undo日志就可以由Purge线程删除了。

用于MVCC

因为Undo日志只在Read Commited、Repeatable Read这2个隔离级别下才服务于MVCC,所以接下来的内容的都是以Read Commited、Repeatable Read隔离级别为前提的。

trx_sys->max_trx_id表示的是将要分配给下一个即将开始的事务的事务ID(trx_id),或者是即将要提交的事务的事务提交号(trx_no),也就是说Innodb中trx_id、trx_no使用的是同一个自增序列

ReadView相当于一个快照,保存了ReadView创建时数据库中活跃事务的ID列表、即将分配给下一个事务的事务ID(属性名为:m_low_limit_no)。

Purge线程负责删除Undo日志,它需要找到一个判断标准来决定Undo日志能不能删除,这个判断标准就是ReadView中的m_low_limit_no属性。 Purge线程会复制数据库中活跃的最早创建的ReadView,此ReadView中的m_low_limit_no属性的值为ReadView创建时,数据库中trx_sys->max_trx_id属性的值。 如果当时数据库中没有活跃的ReadView,会创建一个新的ReadView,并且把新创建的ReadView的m_low_limit_no属性的值设置为trx_sys->max_trx_id属性的值。

事务在提交时,会把Undo日志中的trx_no属性设置为trx_sys->max_trx_id属性的值。如果Undo日志中的trx_no的值小于ReadView中的m_low_limit_no的值,说明生成该Undo日志的事务在创建ReadView时就已经提交了,那么Undo日志对应的行数据就是已经提交了的数据,ReadView就可以直接读取最新的已提交的行数据,而不需要读取Undo日志了,此时Undo日志就可以删除了。

上面说了这一堆,总结起来就是一句话:Purge线程清理Undo日志时,判断Undo日志中的trx_no属性的值小于数据库中当前最早创建的ReadView的m_low_limit_no属性的值,该Undo日志就可以删除。




欢迎扫码关注公众号,我们一起学习更多 MySQL 知识: