天天看点

Mysql知识延展(六)Undo Log日志

前言

Undo log

InnoDB MVCC

事务特性的重要

组成部分

,同时可以提供

数据回滚

。当我们对记录做了

变更操作

时就会产生

undo记录

,Undo记录默认被记录到系统表空间(ibdata)中,但从

5.6

开始,也可以使用

独立的Undo 表空间

Undo记录中存储的是

老版本数据

,当一个

旧的事务

需要

读取数据

时,为了能读取到老版本的数据,需要

顺着undo链

找到满足其

可见性的记录

。当版本链很长时,通常可以认为这是个比较耗时的操作(例如bug#69812)。如果因为某些原因导致

事务失败或回滚

了,可以

借助

undo进行回滚

大多数对数据的

变更操作

包括

INSERT/DELETE/UPDATE

,其中

INSERT

操作在事务提交前只对当前事务可见,因此产生的Undo日志可以在

事务提交后直接删除

(谁会对刚插入的数据有可见性需求呢!!),而对于

UPDATE/DELETE

则需要

维护多版本

信息,在InnoDB里,UPDATE和DELETE操作产生的Undo日志被归成一类,即

update_undo

本文是对整个Undo生命周期过程的阐述,代码分析基于当前最新的MySQL5.7版本。

Undo Log

undo log和

redo log记录物理日志

不一样,它是

逻辑日志

。可以认为当

delete

一条记录时,undo log中会记录一条

对应的insert

记录,反之亦然,当

update

一条记录时,它记录一条

对应相反的update

记录。当执行rollback时,就可以从undo log中的逻辑记录

读取到相应

的内容并

进行回滚

。有时候应用到

行版本控制

的时候,也是通过undo log来实现的:当读取的某一行被其他事务锁定时,它可以从undo log中分析出该行记录的

历史数据

是什么,让用户实现

非锁定一致性

读取。

为了保证事务并发操作时,在写各自的undo log时不产生冲突,InnoDB采用

回滚段

的方式来维护undo log的并发写入和持久化。回滚段实际上是一种 Undo

文件组织方式

每个回滚段

1024

undo log slot

组成。

每个undo操作

在记录的时候

占用一个undo log slot

。另外,

undo log也会产生redo log

,因为undo log也要

实现持久性

保护。

存储

MySQL5.5以后可以支持128个rollback segment,即支持128*1024个undo操作,还可以通过变量

innodb_undo_logs

(5.6版本以前该变量是 innodb_rollback_segments )

自定义

多少个

rollback segment

默认值为128

。undo log

默认存放

共享表空间

中。如果开启了

innodb_file_per_table

,将放在每个表的

.ibd

文件中。

在MySQL5.6中,undo的存放位置还可以通过变量

innodb_undo_directory

自定义存放目录

,默认值为"."表示datadir。

默认rollback segment全部写在一个文件中,但可以通过设置变量

innodb_undo_tablespaces

平均分配到多少个文件中。该变量

默认值为0

,即

全部写入一个表空间文件

。该变量为静态变量,只能在数据库示例停止状态下修改,如写入配置文件或启动时带上对应参数。但是innodb存储引擎在启动过程中提示,

不建议修改为非0

的值

delete/update操作的内部机制

事务提交

的时候,innodb

不会立即删除

undo log,因为

后续

还可能会用到undo log,如

隔离级别为repeatable read

时,

事务读取

的都是

开启事务时

最新提交行版本

,只要

该事务不结束

该行版本就不能删除

,即undo log不能删除。

但是在

事务提交

的时候,会将该事务对应的

undo log放入到删除列表

中,

未来通过purge来删除

。并且提交事务时,还

会判断undo log分配的页是否可以重用

,如果可以重用,则会分配给后面来的事务,

避免

为每个独立的事务

分配独立的undo log页

浪费存储空间和性能

通过undo log记录delete和update操作的结果发现:(insert操作无需分析,就是插入行而已)

  • delete

    操作实际上

    不会直接删除

    ,而是将delete对象

    打上delete flag

    ,标记为删除,

    最终

    的删除操作是

    purge

    线程完成的。
  • update

    分为

    两种

    情况:update的列

    是否是主键列

    • 如果

      不是主键列

      ,在undo log中直接

      反向记录

      是如何

      update

      的。即update是直接进行的。
    • 如果

      是主键列

      ,update分两部执行:

      先删除

      该行,

      再插入

      一行目标行。

参考undo数据结构:http://mysql.taobao.org/monthly/2015/04/01/

本文参考:https://www.cnblogs.com/f-ck-need-u/archive/2018/05/08/9010872.html

继续阅读