- GreatSQL社区原创内容未经受权不得随便应用,转载请分割小编并注明起源。
- GreatSQL是MySQL的国产分支版本,应用上与MySQL统一。
文章导读:
什么是Undo Log?
Undo:
意为撤销或勾销,以撤销操作为目标,返回某个状态的操作。
Undo Log:
数据库事务开始之前,会将要批改的记录放到Undo日志里,当事务回滚时或者数据库解体时,能够利用UndoLog撤销未提交事务对数据库产生的影响。
Undo Log是事务原子性的保障。在事务中更新数据的前置操作其实是要先写入一个Undo Log
如何了解Undo Log
事务须要保障原子性,也就是事务中的操作要么全副实现,要么什么也不做。但有时候事务执行到一半会呈现一些状况,比方:
- 状况一:事务执行过程中可能遇到各种谬误,比方服务器自身的谬误,操作系统谬误,甚至是忽然断电导致的谬误。
- 状况二:DBA能够在事务执行过程中手动输出ROLLBACK语句完结以后事务的执行。
以上状况呈现,咱们须要把数据改回原先的样子,这个过程称之为回滚。
每当咱们要对一条记录做改变时(这里的改变能够指INSERT、DELETE、UPDATE
),都须要"留一手"——把回滚时所需的货色记下来。比方:
- 你插入一条记录时,至多要把这条记录的主键值记下来,之后回滚的时候只须要把这个主键值对应的记录删掉就好了。(对于每个
INSERT
, InnoDB存储引擎会实现一个DELETE
) - 你删除了一条记录,至多要把这条记录中的内容都记下来,这样之后回滚时再把由这些内容组成的记录插入到表中就好了。(对于每个
DELETE
,InnoDB存储引擎会执行一个INSERT
) - 你批改了一条记录,至多要把批改这条记录前的旧值都记录下来,这样之后回滚时再把这条记录更新为旧值就好了。(对于每个
UPDATE
,InnoDB存储引擎会执行一个相同的UPDATE
,将批改前的行放回去)
MySQL把这些为了回滚而记录的这些内容称之为撤销日志
或者回滚日志
(即Undo Log)。留神,因为查问操作(SELECT)并不会批改任何用户记录,所以在杳询操作行时,并不需要记录相应的Undo日志
此外,Undo Log会产生Redo Log
,也就是Undo Log的产生会随同着Redo Log的产生,这是因为Undo Log也须要持久性的爱护。
Undo Log的性能
- 提供数据回滚-原子性
当事务回滚时或者数据库解体时,能够利用Undo Log来进行数据回滚。 - 多个行版本控制(MVCC)-隔离性
即在InnoDB存储引擎中MVCC的实现是通过Undo来实现。当用户读取一行记录时,若该记录曾经被其余事务占用,以后事务能够通过Undo读取之前的行版本信息,以此实现非锁定读取。
Undo Log的存储构造
- 回滚段与undo页
InnoDB对Undo Log的治理采纳段的形式,也就是回滚段(rollback segment)
。每个回滚段记录了1024个Undo Log segment
,而在每个Undo Log segment段中进行Undo页
的申请。
在InnoDB1.1版本
之前(不包含1.1版本),只有一个rollback segment,因而反对同时在线的事务限度为1024。尽管对绝大多数的利用来说都曾经够用。
从1.1版本开始InnoDB反对最大128个rollback segment
,故其反对同时在线的事务限度进步到了128*1024
。
mysql> show variables like 'innodb_undo_logs';+------------------+-------+| Variable_name | Value |+------------------+-------+| innodb_undo_logs | 128 |+------------------+-------+
尽管InnoDB1.1版本反对了128个rollback segment,然而这些rollback segment都存储于共享表空间ibdata中。从lnnoDB1.2版本开始,可通过参数对rollback segment做进一步的设置。这些参数包含:
innodb_undo_directory:
设置rollback segment文件所在的门路。这意味着rollback segment能够寄存在共享表空间以外的地位,即能够设置为独立表空间。该参数的默认值为“./”,示意以后InnoDB存储引擎的目录。
innodb_undo_logs:
设置rollback segment的个数,默认值为128。在InnoDB1.2版本中,该参数用来替换之前版本的参数innodb_rollback_segments。
innodb_undo_tablespaces:
设置形成rollback segment文件的数量,这样rollback segment能够较为均匀地散布在多个文件中。设置该参数后,会在门路innodb_undo_directory看到undo为前缀的文件,该文件就代表rollback segment文件。
- 回滚段与事务
1.每个事务只会应用一个回滚段(rollback segment),一个回滚段在同一时刻可能会服务于多个事务。
2.当一个事务开始的时候,会制订一个回滚段,在事务进行的过程中,当数据被批改时,原始的数据会被复制到回滚段。
3.在回滚段中,事务会一直填充盘区,直到事务完结或所有的空间被用完。如果以后的盘区不够用,事务会在段中申请扩大下一个盘区,如果所有已调配的盘区都被用完,事务会笼罩最后的盘区或者在回滚段容许的状况下扩大新的盘区来应用。
4.回滚段存在于Undo表空间中,在数据库中能够存在多个Undo表空间,但同一时刻只能应用一个Undo表空间。
5.当事务提交时,InnoDB存储引擎会做以下两件事件:
1.将Undo Log放入列表中,以供之后的purge(荡涤、革除)操作
2.判断Undo Log所在的页是否能够重用(低于3/4能够重用),若能够调配给下个事务应用
- 回滚段中的数据分类
未提交的回滚数据(uncommitted undo information):
该数据所关联的事务并未提交,用于实现读一致性,所以该数据不能被其余事务的数据笼罩。
曾经提交但未过期的回滚数据(committed undo information):
该数据关联的事务曾经提交,然而仍受到undo retention参数的放弃工夫的影响。
事务曾经提交并过期的数据(expired undo information):
事务曾经提交,而且数据保留工夫曾经超过undo retention参数指定的工夫,属于曾经过期的数据。当回滚段满了之后,会优先笼罩"事务曾经提交并过期的数据"。
- Undo页的重用
当咱们开启一个事务须要写Undo log的时候,就得先去Undo Log segment
中去找到一个闲暇的地位,当有空位的时候,就去申请Undo页,在这个申请到的Undo页中进行Undo Log的写入。咱们晓得MySQL默认一页的大小是16k
。
为每一个事务调配一个页,是十分节约的(除非你的事务十分长),假如你的利用的TPS(每秒解决的事务数目)为1000,那么1s就须要1000个页,大略须要16M的存储,1分钟大略须要1G的存储。如果照这样上来除非MySQL清理的十分勤快,否则随着工夫的推移,磁盘空间会增长的十分快,而且很多空间都是节约的。
于是Undo页就被设计的能够重用了,当事务提交时,并不会立即删除Undo页。因为重用,所以这个Undo页可能混杂着其余事务的Undo Log。Undo Log在commit后,会被放到一个链表中,而后判断Undo页的应用空间是否小于3/4,如果小于3/4的话,则示意以后的Undo页能够被重用,那么它就不会被回收,其余事务的Undo Log能够记录在以后Undo页的前面。因为Undo Log是离散的,所以清理对应的磁盘空间时,效率不高。
- Undo Log日志的存储机制
如上图,能够看到,Undo Log日志外面不仅寄存着数据更新前的记录,还记录着RowID
、事务ID
、回滚指针
。其中事务ID每次递增,回滚指针第一次如果是INSERT语句的话,回滚指针为NULL,第二次UPDATE之后的Undo Log的回滚指针就会指向刚刚那一条Undo Log日志,以此类推,就会造成一条Undo Log的回滚链,不便找到该条记录的历史版本。
Undo Log的工作原理
在更新数据之前,MySQL会提前生成Undo Log日志,当事务提交的时候,并不会立刻删除Undo Log,因为前面可能须要进行回滚操作,要执行回滚(ROLLBACK)操作时,从缓存中读取数据。Undo Log日志的删除是通过通过后盾purge线程进行回收解决的。
- 1、事务A执行UPDATE操作,此时事务还没提交,会将数据进行备份到对应的Undo Buffer,而后由Undo Buffer长久化到磁盘中的Undo Log文件中,此时Undo Log保留了未提交之前的操作日志,接着将操作的数据,也就是test表的数据长久保留到InnoDB的数据文件IBD。
- 2、此时事务B进行查问操作,间接从Undo Buffer缓存中进行读取,这时事务A还没提交事务,如果要回滚(ROLLBACK)事务,是不读磁盘的,先间接从Undo Buffer缓存读取。
Undo Log的类型
在InnoDB存储引擎中,Undo Log分为:
- insert Undo Log
insert Undo Log是指在insert操作中产生的Undo Log。因为insert操作的记录,只对事务自身可见,对其余事务不可见(这是事务隔离性的要求),故该Undo Log能够在事务提交后间接删除。不须要进行purge操作。 - update Undo Log
update Undo Log记录的是对delete和update操作产生的Undo Log。该Undo Log可能须要提供MVCC机制,因而不能在事务提交时就进行删除。提交时放入Undo Log链表,期待purge线程进行最初的删除。
Undo Log的生命周期
简要生成过程
以下是Undo+Redo事务的简化过程:
假如有2个数值,别离为A=1和B=2,而后将A批改为3,B批改为4
1. start transaction;2.记录A=1到Undo Log;3. update A = 3;4.记录A=3 到Redo Log;5.记录B=2到Undo Log;6. update B = 4;7.记录B = 4到Redo Log;8.将Redo Log刷新到磁盘;9. commit
- 在1-8步骤的任意一步零碎宕机,事务未提交,该事务就不会对磁盘上的数据做任何影响。
如果在8-9之间宕机。
- Redo Log 进行复原
- Undo Log 发现有事务没实现进行回滚。
- 若在9之后零碎宕机,内存映射中变更的数据还来不及刷回磁盘,那么零碎复原之后,能够依据Redo Log把数据刷回磁盘。
流程图:
Undo Log的配置参数
innodb_max_undo_log_size:
undo日志文件的最大值,默认1GB,初始化大小10M
innodb_undo_log_truncate:
标识是否开启主动膨胀Undo Log表空间的操作
innodb_undo_tablespaces:
设置独立表空间的个数,默认为0,标识不开启独立表空间,undo日志保留在ibdata1中
innodb_undo_directory:
undo日志存储的目录地位
innodb_undo_logs: 回滚的个数 默认128
参考文章
- 《MySQL是怎么运行的--从根儿上了解MySQL》—小孩子4919
Enjoy GreatSQL :)
## 对于 GreatSQL
GreatSQL是由万里数据库保护的MySQL分支,专一于晋升MGR可靠性及性能,反对InnoDB并行查问个性,是实用于金融级利用的MySQL分支版本。
相干链接: GreatSQL社区 Gitee GitHub Bilibili
GreatSQL社区:
欢送来GreatSQL社区发帖发问
https://greatsql.cn/
技术交换群:
微信:扫码增加GreatSQL社区助手
微信好友,发送验证信息加群
。