MySQL-- InnoDB存储引擎-撤销日志 ( undo log )(2-4)

254 阅读6分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第28天,点击查看活动详情

5. 撤销日志 ( undo log )

  • undo log 基本概念

    undo log是一种用于撤销回退的日志,在数据库事务开始之前,MySQL会先记录更新前的数据到 undo log日志文件里面,当事务回滚时或者数据库崩溃时,可以利用 undo log来进行回退。

    Undo Log产生和销毁:Undo Log在事务开始前产生;事务在提交时,并不会立刻删除undo log,innodb会将该事务对应的undo log放入到删除列表中,后面会通过后台线程purge thread进行回收处理。

    注意: undo log也会产生redo log,因为undo log也要实现持久性保护。

  • undo log的作用

    1. 提供回滚操作【undo log实现事务的原子性

      在数据修改的时候,不仅记录了redo log,还记录了相对应的undo log,如果因为某些原因导致事务执行失败了,可以借助undo log进行回滚。

      undo log 和 redo log 记录物理日志不一样,它是逻辑日志。可以认为当delete一条记录时,undo log中会记录一条对应的insert记录,反之亦然,当update一条记录时,它记录一条对应相反的update记录。

    2. 提供多版本控制(MVCC)【undo log实现多版本并发控制(MVCC)

      MVCC,即多版本控制。在MySQL数据库InnoDB存储引擎中,用undo Log来实现多版本并发控制(MVCC)。当读取的某一行被其他事务锁定时,它可以从undo log中分析出该行记录以前的数据版本是怎样的,从而让用户能够读取到当前事务操作之前的数据【快照读】。

      快照读:

      SQL读取的数据是快照版本【可见版本】,也就是历史版本,不用加锁,普通的SELECT就是快照读。

      当前读:

      SQL读取的数据是最新版本(最新版本指的是修改且已经提交的数据)。除了在执行修改语句的时候,需要执行当前读,然后再更新数据之外,select语句也有可能是当前读,比如: select ... lock in share mode、select ... for update。

  • undo log 的工作原理

    在更新数据之前,MySQL会提前生成undo log日志,当事务提交的时候,并不会立即删除undo log,因为后面可能需要进行回滚操作,要执行回滚(rollback)操作时,从缓存中读取数据。

    undo log日志的删除是通过通过后台purge线程进行回收处理的。

image.png

  1. 事务A执行update更新操作,在事务没有提交之前,会将旧版本数据备份到对应的undo buffer中,然后再由undo buffer持久化到磁盘中的undo log文件中, 之后才会对user进行更新操作,然后持久化到磁盘.
  2. 在事务A执行的过程中,事务B对User进行了查询

Undo log的存储机制

为了保证事务并发操作时,在写各自的undo log时不产生冲突,InnoDB采用回滚段的方式来维护undo log的并发写入和持久化。

rollback segment 称为回滚段 共有128个,每个回滚段中有1024个undo log segment ,即支持128*1024undo操作,最多支持131072个并发事务执行。

接下来我们一起来看一下,一条INSERT语句的undo log具体都存储着哪些内容

1) 事务ID

事务执行过程中在对某个表执行增、删、改操作时,InnoDB就会给这个事务分配一个唯一的事务ID。

可以通过 information_schema.INNODB_TRX 来查询当前系统中运行的事务信息.

START TRANSACTION;
    select * from test1.a1;
commit;
--trx_id 就是事务ID,InnoDB 在内存维护了一个全局变量来表示事务ID,每当要分配一个事务ID时,就获取这个变量值,然后把这个变量自增1
select 
    trx_id , 
    trx_state ,
    trx_started,
    trx_isolation_level
from information_schema.INNODB_TRX;

2) 行记录的隐藏列

InnoDB引擎管理的数据表中每行行记录,都存在着三个隐藏列:

image.png

  • DB_ROW_ID : 如果没有为表显式的定义主键,并且表中也没有定义唯一索引,那么InnoDB会自动为表添加一个row_id的隐藏列作为主键。
  • DB_TRX_ID : 事务中对某条记录做增删改时,就会将这个事务的事务ID写入到trx_id中.
  • DB_ROLL_PTR: 回滚指针,指向undo log的指针

3) INSERT语句的undo log回滚日志结构

插入一条数据对应的undo操作其实就是根据主键删除这条数据就行了。所以 insert 对应的 undo log 主要是把这条记录的主键记录上

image.png

  • start、end:指向记录开始和结束的位置。
  • 主键列信息:记录INSERT这行数据的主键ID信息,或者唯一列信息。
  • table id:表空间ID。
  • undo no:在当前事务中 undo log 的编号,从0开始。
  • undo type:undo log 的类型,insert语句的undo log类型是 TRX_UNDO_INSERT_REC

4) undo回滚链

通过一个事物操作,我们一起来看一下回滚链的形成.

image.png

undo log 相关参数

MySQL 与undo相关的参数设置:

mysql> show variables like '%undo%';
+--------------------------+------------+
| Variable_name            | Value      |
+--------------------------+------------+
| innodb_max_undo_log_size | 1073741824 |
| innodb_undo_directory    | ./         |
| innodb_undo_log_truncate | OFF        |
| innodb_undo_logs         | 128        |
| innodb_undo_tablespaces  | 0          |
+--------------------------+------------+
​
mysql> show global variables like '%truncate%';
+--------------------------------------+-------+
| Variable_name                        | Value |
+--------------------------------------+-------+
| innodb_purge_rseg_truncate_frequency | 128   |
| innodb_undo_log_truncate             | OFF   |
+--------------------------------------+-------+
  • innodb_max_undo_log_size

    表示每一个undolog对应的日志文件的最大值,默认最大值为1GB大小,默认初始化大小为10MB。

    日志文件达到该阈值之后,且参数 innodb_undo_log_truncate=ON,才会触发truncate回收(收缩)动作,被truncate后的表空间文件大小缩小到undolog表空间数据文件默认的1OMB大小。否则即便是到达最大值之后,也不会自动回收undolog的表空间。

  • innodb_undo_directory

    指定undo log日志的存储目录,默认值为 ./。

  • innodb_undo_logs

    在MySQL5.6版本之后,可以通过此参数自定义多少个rollback segment,默认值为128。

  • innodb_undo_tablespaces

    设置undo独立表空间个数,范围为0-128, 默认为0,0表示表示不开启独立undo表空间 且 undo日志存储在ibdata文件中。

    什么时候需要来设置这个参数 ?

    当DB写压力较大时,可以设置独立undo表空间,把undo从 ibdata文件中分离开来,指定 innodb_undo_directory 目录存放,可以制定到高速磁盘上,加快undo log 的读写性能。

  • innodb_undo_log_truncate

    表示是否开启自动收缩undolog的表空间的操作。如果配置为ON,并且配置了2个或2个以上的undolog表空间数据文件,当某一个日志文件大小超过设置的最大值之后,就会自动的收缩表空间数据文件。

    在回收表空间数据文件的时候,被回收的表空间数据文件会临时下线,为了保证undolog一直有地方可以写,此时要保证至少还有1个undolog日志文件是在线的。这就是要求innodb_undo_tablespaces>=2的根本原因