带着问题去学习总是事半功倍的,最近在重温MySQL架构,这里面不得不又提起两日志大将,redo和undo了。所以想着提笔记录一下也做一个重新的梳理。
开篇问题: 1.show engine innodb status中的history list length是哪种对象的长度? 2.history list length 什么时候会被清理? 3.history list length 为什么该值很大的时候,系统多少会有点问题? 4.关于 undo log清理的参数 innodb_purge_batch_size 文档中提过一个128次迭代,这个迭代指的是什么操作的迭代次数?innodb_purge_batch_size参数设置的清理对象为? 5.history list length 和 待purge的delete marked 对象是什么关系? 6.MySQL较低版本中出现的ibdata空间很大的问题和undo log有什么关系?
1.表空间 在MySQL5.6及之前,undo log都是存储于MySQL系统表空间的,之后才出现了undo log独立表空间。MySQL8.0.3开始独立undo表空间的默认个数从0改为2,最大128个。 UNDO log的页类型为FIL_PAGE_UNDO_LOG,这些页面可以从系统表空间中分配,也可以从undo tablespace中分配。 在系统表空间的第5号页面中有一个8x128的位置存放着128个rollback segment header。
2.段
undo log通过回滚段进行管理,每个undo log tablespace默认128个回滚段,以round-robin的方式进行分配。这128号回滚段可分为2类,第0号、33-127号为一类,对普通表进行的改动产生的undo log则从这类段中分配。1-32号为对临时表做记录改动时用到的表空间。0号回滚段必须在系统表空间中(ibdata文件),第1-32号必须在临时表空间中(ibtmp1文件)。做这样的区分原因主要是,系统重启后,临时表的undo表空间是不需要被恢复的,所以不需要记录undo log页面修改时的redo log。 segement同其他tablespace下的段管理一样,都是有一些零散页面以及一些完整的区组成。 每个段对应一个rollback segement header页面,其中存放了1024个undo log 页面链表的first undo page的页号,可以称之为 undo slot。rollback segement header中记录着 undo 页面的最大值、HISTORY链表占用的页面数量、HISTORY链表的基节点、undo slot集合(页号)。
3.链表
undo log会按照操作类型的不同存放不同的链表,主要有INSERT和UPDATE两大类。除此之外,还会按照普通表操作和临时表操作存放不同的链表,所以一个事务最多会涉及到4条undo链表。 还有一个概念为 垃圾链表 和 版本链。
4.页面
undo页面由链表管理,链表的base node存放在第一个undo log 页面的 undo log segment header中。list node信息存放在第一个页面的undo page header中。
undo log segement header描述关于段的信息。主要包括的信息有:1)本undo页面链表处于什么状态(AVCTIVE、CACHED、TO_FREE、TO_PURGE、PREPARE)2)undo页面链表对应的segment信息 3)基节点信息。
undo log header存储关于一个事务产生的一组undo log的信息,包括TRX_ID、XID、TRX_NO、本组日志第一条日志的偏移量、是否包括del mark产生的undo log、上/下一组日志偏移、是否由DDL操作产生、一个12字节的List Node结构,代表一个称之为History链表的节点。
5.重用
insert 类型的undo页面可以在事务提交之后被重用(链表只包含一个undo log页面,该页面已经使用空间小于整个页面的3/4)。update 类型的undo log页面在事务提交之后不能被重用,需要用于MVCC。
6.分配
对于一个新的rollback segment header来说,其中的undo slot均为FIN_NULL值,说明该slot不指向任何一个页面,新事务从第一个slot开始,在表空间中创建一个undo log segment,然后从其中申请一个undo 页面作为 first undo 页面,然后将undo slot的值设置为刚刚申请的页号。 如果undo slot对应的链表可以被重用则会被加入 insert undo cache链表/update cache 链表,新事务会优先在cache链表中找undo slot,没有再去找rollback segment header。 如果undo slot不符合被重用的条件,insert undo 链表会被设置为TO_FREE状态,update undo链表会被设置为TO_PURGE状态,将undo slot设置为FIN_NULL,然后将本次事务写入的一组undo 放到HOSTORY链表中。
7.清理
当事务提交时,事务对应的回滚段会被加入到purge_queue,该queue是以第一个提交事务的trx_x:no作为key的优先级队列,purge_sys:view表示所有全局视图链表中最老的一个视图。当trx_x:no < purge_sys:view时候,就可以被清理了。 undo log的清理分为两个阶段:undo_purge 和undo_truncate 其中undo_purge是清理TRX_UNDO_DEL_MARK类undo对应的recode,由参数innodb_purge_batch_size控制每次清理的record数量。在完成一批undo record的清理之后再进行真正的undo log的清理,称之为 undo_truncate,由参数innodb_rseg_truncate_frequency控制清理的频次。
8.关于purge阶段的UNDO类型
row_purge_record_func 清理 TRX_UNDO_DEL_MARK_REC 类型的undo record, 记录被直接标记删除的,需要物理清理聚簇索引和二级索引, row_purge_upd_exist_or_extern清理TRX_UNDO_UPD_EXIST_REC(不更新主键的情况,包括就地更新和先删除再插入类)该类型的undo record, 聚簇索引被in-place更新但二级索引顺序可能发生改变,二级索引更新为 删除+插入,此时需要根据回滚段去检查耳机索引记录是否发生改变,并做清理操作。
9.问题答案,你知道了吗?