MySQL事务特性之一就是要保证原子性,一组SQL要么全部成功、要么全部失败。当事务进行过程中,如果出现失败或者异常情况要进行回滚,回到之前最初的样子,要这样实现就要需要把之前的数据记录下来。
undo log可以称为撤销日志、undo 日志,它记录着事务回滚前的数据。
官方定义:
❝A storage area that holds copies of data modified by active transactions. ❞
翻译过来就是undo log是保存活动事务修改的数据副本的存储区域。
undo 日志只记录事务中的增删改操作,查询并不会记录,因为查询不会修改数据。undo 日志存在于undo日志段中,undo日志段包含在回滚段中。
undo日志段(undo log segment)是undo日志的集合。undo 日志段包含在回滚段中,一个undo日志段可能包含来自多个事务的undo日志,一个undo日志段一次只能被一个事务使用,但是在事务提交或回滚时,释放undo日志段以后可以重用它。undo日志段也可以被称为“undo segment(undo 段)”。
回滚段(rollback segment)是包含undo日志的存储区域。回滚段通常位于系统表空间中。从MySQL 5.6开始,回滚段可以存储在undo表空间中,从MySQL 5.7开始,回滚段也被分配到全局临时表空间。
InnoDB最多支持128个回滚段,其中有1个回滚段用于系统表空间,32个回滚段位于临时表空间,剩余的95个用于undo表空间。
可以通过参数innodb_rollback_segments
修改回滚段的个数,默认是最大值128。要分配多余的回滚段给undo表空间的话,回滚段在修改的时候值要大于33。
回滚段实际上是一种Undo 文件组织方式,每个回滚段又由多个undo slot组成。回滚段支持的事务数取决于回滚段中的撤销槽(undo slot)位数和每个事务所需的undo日志数。根据InnoDB页面的大小,回滚段中undo槽的数量是不同的。
InnoDB页大小 | Undo Slot在回滚的中的数量(InnoDB页大小 / 16) |
---|---|
4096 (4KB) | 256 |
8192 (8KB) | 512 |
16384 (16KB) | 1024 |
32768 (32KB) | 2048 |
65536 (64KB) | 4096 |
InnoDB页大小默认为16k,所以Undo Slot数量默认为1024。
一个事务在以下4种情况会产生undo日志,分别为:
可以发现,大多数对数据的变更操作包括INSERT/DELETE/UPDATE,总的还是分为两类undo 日志,INSERT操作独自占一类,UPDATE和DELETE归为一类。其中INSERT操作在事务提交前只对当前事务可见,因此产生的Undo日志可以在事务提交后直接删除,INSERT操作产生的undo日志称为insert undo ,而对于UPDATE/DELETE则需要维护多版本信息,在InnoDB里,UPDATE和DELETE操作产生的Undo日志被归成一类,称为update undo。
undo日志会按需分配,需要哪类日志就用哪类。比如,如果一个事务同时有INSERT、UPDATE和DELETE操作,那么这4种情况的undo日志就都需要。如果一个事务只有INSERT操作,那就只需要一种undo日志。
事务如果操作的是用户自定义的常规表,那undo日志就会从系统表空间或者undo表空间的回滚段分配。反之,如果事务操作的是用户定义的临时表,那么undo日志就会从临时表空间的回滚段分配。
根据回滚段可以预估出InnoDB 能支持多少个并发读写事务:
(innodb_page_size / 16) * (innodb_rollback_segments - 32)
(innodb_page_size / 16 / 2) * (innodb_rollback_segments - 32)
(innodb_page_size / 16) * 32
(innodb_page_size / 16 / 2) * 32
undo 日志主要有两个作用,事务回滚和作为MVCC的一部分:
上面说的就是事务回滚,主要用于保证事务的原子性。通过undo日志在事务需要回滚的时候,让数据恢复到最初的样子。
undo日志作为MVCC(Multi-Versioin Concurrency Control)版本链的一部分,Undo记录中存储的是老版本数据,当一个旧的事务需要读取数据时,为了能读取到老版本的数据,需要顺着undo链找到满足其可见性的记录。
对于INSERT操作,insert undo在事务提交后,ndo segment就释放了。而对于UPDATE/DELETE操作产生的update undo则比较复杂,。
对于UPDATE/DELETE操作产生的update undo日志,则会加入history list,由后台线程Purge进行清理。
可通过命令show variables like "%undo%"
查看undo日志相关参数:
CREATE TABLESPACE
语句创建undo表空间。undo log是MySQL最重要的日志之一,这里简单介绍了一下undo日志的概念、作用、机制等,算是对undo日志有了大致的了解。
参考资料:
❝https://dev.mysql.com/doc/refman/5.7/en/innodb-undo-logs.html http://mysql.taobao.org/monthly/2015/04/01/ ❞