作用:回顾 + MVCC
类型:insert + update undolog。
删除:前者只有当前事务可见,因此当前事务提交后,就可以直接删除。后者需要后台线程回收。
为什么不需要 delete undolog?删除标记位,假删除。

undo log 概念

undo log 是  逻辑日记 、回滚日记。回滚日志会先于数据持久化到磁盘上。这样就保证了即使遇到数据库突然宕机等情况,当用户再次启动数据库的时候,数据库还能够通过查询回滚日志来回滚将之前未完成的事务。

逻辑格式的日志,在执行 undo 的时候,仅仅是将数据从逻辑地址上恢复至事务之前的状态,而不是从物理页面上操作实现的。

undo log 作用

回滚数据
当程序发生异常错误时等,根据执行 undo log 就可以回滚到事务之前的数据状态,保证原子性。

保证 MVCC 视图的一致性
通过 undo log 找到对应的数据版本号,是保证 MVCC 视图的一致性的必要条件。

undo log 类型

在 InnoDB 存储引擎中,undo log 分为:

  • insert undo log
  • update undo log

undo log 存储结构

rollback segment 回滚段

undo log  的存储由 InnoDB 存储引擎实现,数据保存在 InnoDB 的数据文件中。在 InnoDB 存储引擎中,undo log  是采用分段(segment)的方式进行存储的。rollback segment  称为回滚段,每个回滚段中有 1024 个  undo log segment

在 MySQL5.5 之前,只支持 1 个  rollback segment,也就是只能记录 1024 个 undo 操作。在 MySQL5.5 之后,可以支持 128 个  rollback segment,分别从 resg slot0 - resg slot127,每一个 resg slot,也就是每一个回滚段,内部由 1024 个  undo segment  组成,即总共可以记录 128 * 1024 个 undo 操作。

回滚段与事务

  1. 每个事务只会使用一个回滚段,一个回滚段在同一时刻可能会服务于多个事务。
  2. 当一个事务开始的时候,会制定一个回滚段,在事务进行的过程中,当数据被修改时,原始的数据会被复制到回滚段。
  3. 在回滚段中,事务会不断填充盘区,直到事务结束或所有的空间被用完。如果当前的盘区不够用,事务会在段中请求扩展下一个盘区,如果所有已分配的盘区都被用完,事务会覆盖最初的盘区或者在回滚段允许的情况下扩展新的盘区来使用。
  4. 回滚段存在于 undo 表空间中,在数据库中可以存在多个 undo 表空间,但同一时刻只能使用一个 undo 表空间。
  5. 当事务提交时,InnoDB 存储引擎会做以下两件事情:
    将 undo log 放入列表中,以供之后的 purge 操作
    判断 undo log 所在的页是否可以重用,若可以分配给下个事务使用

undo log 存储内容

undo log  日志里面不仅存放着数据更新前的记录,还记录着 RowID、事务 ID、回滚指针。其中事务 ID 每次递增,回滚指针第一次如果是 insert 语句的话,回滚指针为 NULL,第二次 update 之后的  undo log  的回滚指针就会指向刚刚那一条 undo log 日志,依次类推,就会形成一条 undo log 的回滚链,方便找到该条记录的历史版本。

undo log 生成过程

简要生成过程

找不到“mysql log.png”。

详细生成过程

事务开始之前,将当前事务版本生成 undo log,undo 也会产生 redo 来保证 undo log 的可靠性。每一次写操作都会生成 undo log,比如 update 操作,会生成一条更新前的记录信息,比如主键 ID,需要更新的字段以及字段对应的旧值。对于 DELETE 操作,在 delete mark 操作时,会获取该条记录最近一次的 undo log 记录,生成的新的 undo log 记录了旧记录的 trx_id(事务编号) 和 old roll_pointer(上一个 undo log 的位置) ,这样回滚时,就可以直接找到删除之前的 undo log 进行回滚操作。

undo log 删除时机

在更新数据之前,MySQL 会提前生成 undo log 日志,当事务提交的时候,并不会立即删除 undo log,因为后面可能需要进行回滚操作,要执行回滚(rollback)操作时,从缓存中读取数据。undo log 日志的删除是通过通过后台 purge 线程进行回收处理的。

  • 针对于  insert undo log
    因为 insert 操作的记录,只对事务本身可见,对其他事务不可见。故该 undo log 可以在事务提交后直接删除,不需要进行 purge 操作。
  • 针对于  update undo log
    该 undo log 可能需要提供 MVCC 机制,因此不能在事务提交时就进行删除。提交时放入 undo log 链表,等待 purge 线程进行最后的删除。

为什么不需要 delete undolog

对于删除操作,InnoDB 不记录 delete undo log,而是通过保留被删除行的旧版本来实现一致性读取。当一个事务执行删除操作时,InnoDB 并不是真正地从表中删除行,而是给该行打上一个删除标志,并记录该行的版本信息。

一致性读取:当其他事务读取数据时,InnoDB 会检查行的版本信息和删除标记,只返回那些在事务开始时存在且没有被标记为删除的行版本。这样,即使在事务执行删除操作之后,其他事务仍然可以看到删除前的数据版本。

undo log 总结

  • undo log 日记内容不是很多,重点是  回滚  和  多版本控制 MVCC  那块。
  • 生成是事务开始后写 redo log 之前生成,当没有事务需要用到 undo log 时就会被删除
  • 长事务会导致 undo log 过多。因为长事务存在,导致需要保存很多视图快照。
  • 举个例子,如果事务 A 一直存活,那么事务 A 之后产生的事务 B、C… 等等就算提交了,也不会被删除,因为事务 A 需要用到 B、C… 事务去找 A 的版本。所以避免长事务可以减少 undo log 日记量,当然还可以提高性能。