《MySQL是怎么运行的:从根儿上理解MySQL》(23)学习总结

说明

文章的图片来源《MySQL是怎么运行的:从根儿上理解MySQL》,本篇文章只是个人学习总结,欢迎大家买一本正版小册看看,对于mysql是由浅入深的讲解非常细致

23.undo日志(下)

通用链表结构

image-20211106194246620

链表的基节点

image-20211106194358001

FIL_PAGE_UNDO_LOG页面

  • FIL_PAGE_INDEX:存储聚簇索引或者是二级索引的数据页类型
  • FIL_PAGE_TYPE_FSP_HDR:描述存储表空间的头部信息
  • FIL_PAGE_UNDO_LOG:专门用于存储undo页面

image-20211106194845247

undo页面特有的Undo Page Header

image-20211106195022049

  • TRX_UNDO_PAGE_TYPE:存储什么类型的undo日志,分了几个类
    • TRX_UNDO_INSERT:包含TRX_UNDO_INSERT_REC
    • TRX_UNDO_UPDATE:包括TRX_UNDO_DEL_MARK_REC和TRX_UNDO_UPD_EXIST_REC
  • TRX_UNDO_PAGE_START:从页面什么位置开始存储undo日志
  • TRX_UNDO_PAGE_FREE:最后一条日志的偏移量

image-20211106195336732

  • TRX_UNDO_PAGE_NONE:代表一个ListNode结构

Undo页面链表

单个事务中的Undo页面链表

  • 一个事务产生多个日志可能一个页面放不下,就需要多个页面,通过TRX_UNDO_PAGE_NONE链表节点结构进行串联

image-20211106195448032

  • first undo page是第一个页面还记录了链表管理信息,其它就是normal undo page
  • 一个页面只能保存一种类型的undo日志,所以需要两条链表一条是insert,另一条是update

image-20211106195823719

  • 而且对于临时表和普通表的undo日志也需要进行分开记录

image-20211106195929010

但不是一开始就这么分配,具体的分配策略

  • 刚开启事务,不分配undo页面
  • 事务插入记录到普通表,生成insert undo链表
  • 如果事务对普通表更新和删除,那么就分配一个update undo链表
  • 如果事务对临时表更新删除或或者是插入那么就会创建对应的链表

按照需要进行分配

多个事务中的Undo页面链表

不同事务产生的undo日志写入到不同的undo链表中

  • 下面就是对于事务1进行临时表增删改和普通表更新,对事务2进行普通表增删改。

image-20211106200345825

undo日志具体写入过程

image-20211106200506679

Undo Log Segment Header

  • 每一个undo log链表对应着一个段叫undo log segment。链表页面就是在这个段上面去申请。所以对于每个链表的第一个页面first undo page都会有一个undo log segment header的部分。包含了undo log segment的信息

image-20211106200836040

看看这个header的结构

image-20211106200858511

  • TRX_UNDO_STATE:链表处于什么状态

image-20211106200946463

  • TRX_UNDO_LAST_LOG:最后一个Undo Log Header的位置
  • TRX_UNDO_FSEG_HEADER:链表对应段segment header的信息,可以找到对应的INODE Entry
  • TRX_UNDP_PAGE_LIST:undo链表的基节点

Undo Log Header

image-20211106201315397

  • 对于每个事务来说,每条undo页面链表都是一个组,而且每次都是直接插入记录,不够了就继续申请。那么记录组的属性的就是Undo Log Header

image-20211106201530543

  • 属性的意思

image-20211106201608660

image-20211106201855507

image-20211106202130625

重用Undo页面

决定是否可以重用的条件

  • 链表里面只有一个undo页面

如果事务产生undo日志太多,那么就会导致链表需要维护很多的页面。

  • undo页面只是使用了小于页面空间的3/4

链表重用的不同策略

  • insert undo链表

这种值存储TRX_UNDO_INSERT_REC的undo日志,提交之后就没用了,可以直接删除。也就是提交之后就可以覆盖这条链表

image-20211106202714106

  • update undo链表

提交之后不能立刻被删除用于mvcc,那么如果要重用相当于就是写入多组的undo log

image-20211106202848763

回滚段

回滚段的概念

  • 一个事务同时可以拥有4个链表,同一时刻有多个不同事务的undo链表。
  • 所以需要一个Rollback Segment Header存储的是每个链表的first undo page页号这种页号称为undo slot。

image-20211106203401924

  • Rollback Segment Header对应着一个Rollback Segment,但是这个段只有一个页。为了某种目的分配的空间通常就是一个段

Rollback Segment Header对应的各个属性

  • TRX_RSEG_MAX_SIZE:所有undo页面链表的页面之和不能大于max_size
  • TRX_RSEG_HISTORY_SIZE:History链表占用的页面数量
  • TRX_RSEG_HISTORY:History链表的基节点。
  • TRX_RSEG_UNDO_SLOTS:每个链表的first undo page 集合

从回滚段中申请Undo页面链表

没有事务

  • FIL_NULL:说明现在的Rollback Segment Header页面的undo slot没有指向任何页面

现在开始有事务

  • FIL_NULL的话那么就检查回滚段的第一个slot,如果是FIL_NULL那么就去表空间申请一个段(UNDO LOG SEGMENT)并且申请一个页作为first undo page

  • 如果不是FIL_NULL那么就跳到下一个slot

  • 现在说明一下回滚段和上面的undo log segment的一个区别。回滚段存储的主要是每个事务的页面链表的第一个页面,对于undo log segment来说其实就是对于每个事务都有自己的一个段,需要段去管理这些事务的日志,那么取出来的时候就能够一下子顺序IO取出来,因为可能一个事务产生的日志页占用大量的空间。

  • 如果slot满了,那么就会报错,用户可以选择重新执行或者是放弃执行。

如果事务提交了,对于slot的处理

  • 如果是可以重用,也就是slot的链表只占用一个页或者是占用页的空间不到3/4那么这个链表状态TRX_UNDO_STATE就会被设置为TRX_UNDO_CACHED

    • insert链表加入到insert undo cached链表
    • update加入到update undo cached链表

    如果有新事务那么先去cached申请slot,如果没有那么才去Rollback Segment Header页面上去寻找

  • slot如果不符合重用

    • insert链表的TRX_UNDO_STATE被设置为TRX_UNDO_TO_FREE(说明链表可以使用),并且链表对应的段也会被释放掉。slot变为FIL_FULL
    • update链表状态设置TRX_UNDO_TO_PRUGE,slot设置为FIL_FULL并且把事务产生的日志写到History链表上面去。

多个回滚段

  • 回滚段的slot不够那么就创建多几个回滚段,通常是128个回滚段。
  • 每个回滚段对应一个Rollback Segment Header页面

image-20211106210801078

  • 页面的地址存储在上面的这个5号页的128个8字节大小的小格子上。
  • 每个格子的构造指向不同的回滚段

image-20211106210858419

总体结构就是5号页存储回滚段,回滚段存储各种链表slot。

image-20211106210955194

回滚段的分类

  • 0号,33-127号回滚段属于一类,0号存在系统表空间,其它33-127可以存在其它表空间(系统或者是undo表空间)

事务对普通表的修改

  • 1-32:必须要在临时表空间(ibtmp1文件)

事务对临时表的修改

为什么要分类

  • 修改页面之前需要把redo日志写上。那么才能在系统崩溃之后恢复
  • undo日志其实也是一个写过程,也就是和普通页的修改都是要存入redo log的。但是对于修改临时表的undo log来说在运行系统时才有效,也就是不运行就无效,不需要写入redo log,也就不需要恢复了。

为事务分配Undo页面链表详细过程

  • 事务修改表前,先去5号页分配一个回滚段
  • 先查看cached链表是否有slot链表可以重用
  • 那么只能在Rollback Segment Header找到一个可使用的slot分配给事务
  • 如果slot没有分配一个undo log segment那么就分配一个
  • 最后就可以把对应的undo日志写到链表上

回滚段相关配置

  • innodb_rollback_segments普通表对应的回滚段

配置undo表空间

  • innodb_undo_directory指定undo表空间的位置目录
  • innodb_undo_tablespaces定义undo表空间的数量

总结

  • undo log segment就是针对于一个undo链表。如果链表需要申请空间,那么就要去段上面去申请。段其实对应着一个INODE Entry节点

  • 对于多个header的不同作用

    • Undo Log Segment Header主要是对于每个链表段的节点位置和链表的状态(状态主要是用于是否重用,处于什么处理的状态)
    • Undo Page Header:主要就是处理页面的类型、页面存储第一条和最后一条记录的位置还有就是链表结构。
  • 关于重用的过程

    • 判断slot是否能够重用,可重用(对应占用一个页而且占用空间小于3/4)那么就加入链表
    • 下次事务增删改普通表的时候就可以重用这个cached链表上面的slot。
  • 关于链表的分类

    • update
    • insert
  • 回滚段的分类

    • 临时表回滚段
    • 普通表回滚段

    为了让redo log的压力不那么大,因为临时表并不需要写入到redo log,系统崩溃是不需要恢复临时表的。只在系统运行的时候使用

  • 回滚段的作用

    • 保存各个链表头

    • 管理链表重用问题

    • 判断slot是否能够重用,可重用(对应占用一个页而且占用空间小于3/4)那么就加入链表

    • 下次事务增删改普通表的时候就可以重用这个cached链表上面的slot。

  • 关于链表的分类

    • update
    • insert
  • 回滚段的分类

    • 临时表回滚段
    • 普通表回滚段

    为了让redo log的压力不那么大,因为临时表并不需要写入到redo log,系统崩溃是不需要恢复临时表的。只在系统运行的时候使用

  • 回滚段的作用

    • 保存各个链表头
    • 管理链表重用问题

猜你喜欢

转载自blog.csdn.net/m0_46388866/article/details/121202995