undo log 事务回滚操作
undo log 事务回滚操作
在数据库管理系统中,undo log(撤销日志)扮演着至关重要的角色,特别是在事务回滚和数据一致性维护方面。本文将深入探讨undo log的工作原理、相关参数配置以及在事务处理中的具体应用。
undo log 回滚操作
undo是什么
undo日志用于存放数据修改被修改前的值。假设修改 tba
表中 id=2
的行数据,把 Name='B1'
修改为 Name='B2'
,那么undo日志就会用来存放 Name='B1'
的记录。如果这个修改出现异常,可以使用undo日志来实现回滚操作,保证事务的一致性。
- undo是逻辑日志,只是将数据结构和页本身逻辑地恢复到原来的样子。
- 对数据库进行修改的时候,InnoDB存储引擎不但会产生redo,还会产生一定量的undo。这样如果用户执行的事务或语句由于某种原因失败了,又或者用户一条ROLLBACK语句请求失败了,就可以利用这些undo信息将数据回滚到修改之前的样子。
为什么不是物理日志
在多用户并发系统中,可能有数十数千个修改当前页中的某几条数据,同时还有别的事务在对同一个页中另几条记录进行修改。因此不能将一个页回滚到事务开始的样子,采用了逻辑恢复的方式。具体来说:
- 是insert的时候就delete
- 是update的时候就采用相对的update来恢复数据
undo 参数
show variables like "%undo%";
- innodb_undo_log_truncate
InnoDB的purge线程,根据innodb_undo_log_truncate设置开启或关闭、innodb_max_undo_log_size的参数值,以及truncate的频率来进行空间回收和 undo file 的重新初始化。该参数生效的前提是,已设置独立表空间且独立表空间个数大于等于2个。
- innodb_max_undo_log_size
控制最大undo tablespace文件的大小。当启动了 innodb_undo_log_truncate 时,undo tablespace 超过 innodb_max_undo_log_size 阀值时才会去尝试truncate。该值默认大小为 1G,truncate后的大小默认为10M。
- innodb_undo_tablespaces
设置undo独立表空间个数,范围为0-128, 默认为0,0表示表示不开启独立undo表空间 且 undo日志存储在ibdata文件中。该参数只能在最开始初始化MySQL实例的时候指定,如果实例已创建,这个参数是不能变动的,如果在数据库配置文 件 .cnf 中指定innodb_undo_tablespaces 的个数大于实例创建时的指定个数,则会启动失败,提示该参数设置有误。
- innodb_undo_directory
设置rollback segment文件所在位置的路径,这意味着rollback segment可以存放在共享表空间以外的位置,即可以设置为独立表空间,该参数的默认值为”.”,标识当前InnoDB存储引擎的位置的目录
- innodb_undo_log
用来设置rollback segment的个数,默认值为128个
undo空间管理
如果需要设置独立表空间,需要在初始化数据库实例的时候,指定独立表空间的数量。
UNDO内部由多个回滚段组成,即 Rollback segment,一共有128个,保存在ibdata系统表空间中,分别从resg slot0 - resg slot127,每一个resg slot,也就是每一个回滚段,内部由1024个undo segment 组成。
回滚段(rollback segment)分配如下:
- slot 0 ,预留给系统表空间;
- slot 1- 32,预留给临时表空间,每次数据库重启的时候,都会重建临时表空间;
- slot33-127,如果有独立表空间,则预留给UNDO独立表空间;如果没有,则预留给系统表空间;
回滚段中除去32个提供给临时表事务使用,剩下的 128-32=96个回滚段,可执行 96*1024 个并发事务操作,每个事务占用一个 undo segment slot,注意,如果事务中有临时表事务,还会在临时表空间中的 undo segment slot 再占用一个 undo segment slot,即占用2个undo segment slot。如果错误日志中有:Cannot find a free slot for an undo log。则说明并发的事务太多了,需要考虑下是否要分流业务。
回滚段(rollback segment )采用 轮询调度的方式来分配使用,如果设置了独立表空间,那么就不会使用系统表空间回滚段中undo segment,而是使用独立表空间的,同时,如果回滚段正在 Truncate操作,则不分配。
undo log 在事务中的流程
事务在undo log segment分配也写入undo log的同时也会产生redo log,当事务提交时候(commit)
- 将undo log 放入列表中,以供之后的purge(pai rui chi)线程使用
- 判断undo log 所在的页是否可以重用,若可以分配给下个事务使用
- 事务提交后,不能马上删除undo log及undo log所在的页,这是因为还有其他事务需要通过undo log来得到行记录之前的版本,故事务提交将undo log 放入一个链表中,是否可以最终删除undo log及undo log所在页由purge线程来判断
当事务提交时候,首先将undo log放入链表中,判断undo页的使用空间是否小于3/4,则表示undo log可以被重用,之后新的undo log 记录在当前的undo log的后面,由于存放undo log的列表是以记录进行组织的,二undo log可能存放着不同事务的undo log,因此prege操作需要设计磁盘的离散读取操作,是一个比较缓慢的过程,此过程可以设置purge线程的个数来提升回收速度
undo log 种类
- insert undo log是值在insert操作中产生的undo log,因为insert操作记录,只对本身事务可见,对其他事物不可见,顾此undo log可以在事务提交后直接删除.
- insert undo log记录的是直接修改后的操作,录入a +=1,记录的是a=2
- update undo log记录的是对delete和update操作产生的undo log,该undo log可能需要提供MVCC机制,故不能再事务提交后就删除,提交时候记录到undo log链表,等待purge线程进行最后的删除
- delete的是将删除的标记为已删除 delete flag为1,而最终的删除是在pruge操作中完成
- update undo log是删除主键的记录,标记为已删除,产生一条新的逆向过程的记录
查看undo数量
show innodb_engine_status中的TRANSACTIONS history list length
purge thread
负责回收已经使用并分配的undo页,purge操作默认是由master thread中完成的,为了减轻master thread的工作,提高cpu使用率以及提升存储引擎的性能。用户可以在参数文件中添加如下命令来启动独立的purge thread。
innodb_purge_threads=1
从innodb1.2版本开始,可以指定多个innodb_purge_threads来进一步加快和提高undo回收速度。