1.1 基本概念
undo log是逻辑日志,记录了变更操作的反向操作。主要用于事务的回滚 和 一致性非锁定读。根据行为不同undo分为insert undo和update undo。
insert undo log(包含INSERT操作)
在insert操作中产生的undo log,因为insert操作的记录只对事务本身可见。因此该undo log在事务提交后直接删除,不需要进行purge操作。
update undo log(包含UPDATE及DELETE操作)
记录的是对delete和update操作产生的undo log,该log需要提供mvcc机制,因此不能在事务提交时就进行删除。提交时放入undo log链表,等待purge线程进行清除。
1.2 相关参数&视图
mysql> show variables like '%undo%';
+--------------------------+-------------------+
| Variable_name | Value |
+--------------------------+-------------------+
| innodb_max_undo_log_size | 4294967296 |
| innodb_undo_directory | /data/mysql8/data |
| innodb_undo_log_encrypt | OFF |
| innodb_undo_log_truncate | ON |
| innodb_undo_tablespaces | 2 |
+--------------------------+-------------------+
5 rows in set (0.00 sec)
mysql> show variables like '%purge%';
+--------------------------------------+--------------------------------------------+
| Variable_name | Value |
+--------------------------------------+--------------------------------------------+
| gtid_purged | 6ac2c3ad-c5b7-11ea-8d1a-00163e0c8a51:1-304 |
| innodb_max_purge_lag | 0 |
| innodb_max_purge_lag_delay | 0 |
| innodb_purge_batch_size | 300 |
| innodb_purge_rseg_truncate_frequency | 128 |
| innodb_purge_threads | 4 |
| relay_log_purge | ON |
+--------------------------------------+--------------------------------------------+
7 rows in set (0.00 sec)
mysql> select * from INNODB_TABLESPACES where ROW_FORMAT='undo'\G
*************************** 1. row ***************************
SPACE: 4294967279
NAME: innodb_undo_001
FLAG: 0
ROW_FORMAT: Undo
PAGE_SIZE: 16384
ZIP_PAGE_SIZE: 0
SPACE_TYPE: Undo
FS_BLOCK_SIZE: 0
FILE_SIZE: 0
ALLOCATED_SIZE: 0
SERVER_VERSION: 8.0.21
SPACE_VERSION: 1
ENCRYPTION: N
STATE: active
*************************** 2. row ***************************
SPACE: 4294967278
NAME: innodb_undo_002
FLAG: 0
ROW_FORMAT: Undo
PAGE_SIZE: 16384
ZIP_PAGE_SIZE: 0
SPACE_TYPE: Undo
FS_BLOCK_SIZE: 0
FILE_SIZE: 0
ALLOCATED_SIZE: 0
SERVER_VERSION: 8.0.21
SPACE_VERSION: 1
ENCRYPTION: N
STATE: active
2 rows in set (0.00 sec)
mysql> select * from INNODB_BUFFER_PAGE where PAGE_TYPE='UNDO_LOG'limit 1\G
*************************** 1. row ***************************
POOL_ID: 0
BLOCK_ID: 8
SPACE: 4294967279
PAGE_NUMBER: 252
PAGE_TYPE: UNDO_LOG
FLUSH_TYPE: 0
FIX_COUNT: 0
IS_HASHED: NO
NEWEST_MODIFICATION: 0
OLDEST_MODIFICATION: 0
ACCESS_TIME: 3685402668
TABLE_NAME: NULL
INDEX_NAME: NULL
NUMBER_RECORDS: 0
DATA_SIZE: 0
COMPRESSED_SIZE: 0
PAGE_STATE: FILE_PAGE
IO_FIX: IO_NONE
IS_OLD: YES
FREE_PAGE_CLOCK: 0
1 row in set (0.10 sec)
1.3 undo log 结构
undo log是由rollback segment(回滚段),MySQL默认支持支持128个rollback segment,每个rollback segment中有1024个undo log segment。每个undo操作在记录的时候占用一个undo log segment,undo log也会产生redo log,因为undo log也要实现持久性保护。
rollback segment分布:
- slot 0 ,预留给系统表空间;
- slot 1- 32,预留给临时表空间,每次数据库重启的时候,都会重建临时表空间;
- slot33-127,如果有独立表空间,则预留给UNDO独立表空间;如果没有,则预留给系统表空间;
1.4 undo log purge
当事务提交的时候,innodb不会立即删除undo log,因为后续还可能会用到undo log,如隔离级别为RR时,事务读取的都是开启事务时的最新提交行版本,只要该事务不结束,该行版本就不能删除,即undo log不能删除。但是在事务提交的时候,会将该事务对应的undo log放入到删除列表中,未来通过purge线程来删除。并且提交事务时,还会判断undo log分配的页是否可以重用,如果可以重用,则会分配给后面来的事务,避免为每个独立的事务分配独立的undo log页而浪费存储空间和性能。
-
insert操作在事务提交后直接删除。
-
delete操作实际上不会直接删除,而是将delete对象打上delete flag,标记为删除,最终的删除操作是purge线程完成的。
-
update分为两种情况:update的列是否是主键列。
- 如果不是主键列,在undo log中直接反向记录是如何update的。即update是直接进行的。
- 如果是主键列,update分两部执行:先删除该行,再插入一行目标行。
innodb通过innodb_purge_threads
参数控制开启多少个独立的purge线程,然后将innodb_purge_batch_size
定义的批量清除的undo log日志页数分配给purge线程;通过innodb_purge_rseg_truncate_frequency
定义purge线程的清除系统释放回滚段的频率,undo log表空间在其对应的回滚段被释放之前是不能被回收的。默认情况下,清除系统会在回滚段被调用128次之 后执行一次释放回滚段操作。
参考文章
https://www.cnblogs.com/xibuhaohao/p/11947041.html