MySQL百问系列:Undo log 作用

3,581 阅读3分钟

问题

  1. undo log是干什么用的?
  2. undo log 版本链
  3. undo log 存放在那里,什么时候会被释放?

支持回滚和MVCC

我们知道innodb 支撑事务。那么事务其中一个功能是需要支持回滚。
事务中可能设计到增,删,改等操作。那么回滚如和实现呢?

  • 如果事务中新增了一条记录,那么我们记录下这条新增的主键,回滚的时候删除即可。
  • 如果事务中删除了一条记录,那么我们记录下记录的所有信息,回滚的时候原样插入即可。
  • 如果事务中修改了一条记录,那么我们要记录原来的信息,回滚的把原来的信息更新回去就好了。

undo log 就是记录这些用于回滚的信息。
那么MVCC 为什么也是靠undo log来实现的呢?
也许你听说过聚簇索引每条记录有个隐藏字段叫row_id,他的作用是如果不指定主键,它就变成了系统内部的自增主键。同时其实每条记录还有两个字段一个是trx_id,一个是roll_pointer.这个两个字段就是用来实现MVCC功能。

  • trx_id: 修改当前记录的事务id。
  • roll_pointer:只向一个undo log。

每一条undo log记录当然也有trx_id, 和roll_pointer字段。

准备工作:

CREATE TABLE `student` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `age` int(11) NOT NULL,
  `addresss` varchar(255) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`),
  KEY `index_age` (`age`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;

INSERT student VALUES (1,'张一',1,'ssss'),(2,'张二',2,'ssss');

聚簇索引内容类似于一下:

id name age address trx_id roll_pointer
1 张一 1 ssss 10 insert_undo_log 地址
2 张二 2 ssss 10 insert_undo_log 地址

undo log类似于一下:

id name age address trx_id roll_pointer undo id
1 张一 1 ssss 10 0
2 张二 2 ssss 10 1

undo id 的在同一个事务中依次递增的。

update set age=10 where id = 1; #更新语句一
update set age=20 where id = 1; #更新语句二
id name age address trx_id roll_pointer undo id
1 张一 1 ssss 20 指向上一条insert log 地址 0
1 张一 10 ssss 21 上一条undo log 地址 0

几点说明:

  • insert log 在上一个插入事务结束后,会被回收,释放。
  • 更新语句一 ,roll_pointer 会保存上一条插入的insert log。 同时保存更新前的信息。
  • 因为是自动提交事务模式,所以2个update,会产生2个不同的trx_id。
  • 真实的update log 记录的信息结构要复杂的多,会分更新主键,和不更新主键的情况。这里不详细展开。
  • 这种一条条undo log 依据roll_pointer形成的链式结构,就是版本链。

undo log 存放在哪?

在MYSQL 5.6 之后,可以为undo log 分配独立的表空间。
默认表空间的数量为2个,可以设置innodb_undo_tablespaces 来增加数量。
每个表空间又被分为多个回滚段(rollback segment),回滚段的数量可以查看innodb_undo_logs。
每个回滚段就存放了undo log 页。
如果undo log 对应的事务都已经是执行完毕,或者回滚结束的。那么对应的undo log 空间就可以被回收了。
假设有一个长事务,迟迟未被提交,或回滚,那么undo log 会越来越大。严重的会直接导致服务器磁盘空间爆满。所以如果突然服务器磁盘空间使用量快速上升,也可以查看下是否有长事务没有提交,导致undo log占用很大磁盘空间。

总结

undo log 两大作用:

  • 保障事务的原子性。事务中的所有更新语句,要么全被执行,要么全被回滚。通过将同一个trx_id 的undo log 就可以实现回滚同一事务的所有更新语句了。
  • 提供版本链,支持MVCC。undo log 链为实现MVCC 提供了底层的物质基础。为了实现MVCC ,还需要借助Read View 。后续详细讲解MVCC中会详细聊到。