重用的undo日志 (3)—mysql进阶(六十六)

2023-11-20

前面说了undo日志的文件格式,第一页和后面的页是不同的,填入undo日志之前,会先把undo_page_header属性填满,还有undo_segment_header,undo_log_header。List base node存在undo segment header,list node存在每个undo 页面的undo_page_header。

不重用的undo日志 (2)—mysql进阶(六十五)

重用undo页面

前面说了为了提高并发性能,多个事务写入undo日志性能,innoDB每个事务都有单独的undo链表。但这样也会造成内存浪费,针对如果某个事务只执行了很少量的sql,这些undo日志只占用一点点空间,都占用一个事务的链表,是不是太浪费了,于是在事务提交后的某些情况下,重用该事务的undo页面链表。一个链表判断是否可以被重用非常简单:

  1. 该链表只包含一个undo页面

如果一个事务执行过程中产生很多的undo日志,那么可能有非常多的页面加入到undo页面链表中。在该事务提交后,如果将整个链表的页面都重用,意味着即是新的事务并没有向undo页面链表写入很多undo日志,那么该链表也得维护非常多的页面,那些用不到的页面也不能被别的事务使用,这样就造成一种浪费。所以innoDB规定,只有在undo链表包含一个undo页面时,该链表才可以被下一个事务使用。

  1. 该undo页面已经使用的空间小于整个页面空间的3/4。

Insert undo 和update undo重用的策略也是不同的。

Insert undo链表:

Insert只存储trx_undo_insert_rec的undo日志,这种类型在事务提交后就没用了,就可以清楚掉。所以在某个事务提交后,重用这个事务insert undo链表的时候,可以直接把之前事务写入一组undo日志覆盖掉,从头开始写。

假如有一个事务使用insert undo链表,到事务提交时,只想insert undo链表插入3条undo日志,这个insert undo链表只申请了一个undo页面。假设此刻该页面使用空间小于整个空间的3/4,那么下一个事务就可以重用这个insert undo链表(并且链表满足只有一个页面)。假设此刻有一个新事物重用了该insert undo链表,那么把之前的覆盖掉。

Update undo链表:

Insert undo链表在事务提交后,undo日志可以直接删除,但是update 日志不能再事务提交后直接删除(下一章mvcc会介绍为什么不能被删除)。所以后面的如果想重用,就不是覆盖,而是新加一条数据。

回滚段

我们知道一个事务执行最多分配4个undo页面链表。在同一时刻,不同事务拥有的undo页面链表是不同的,为了管理好这些链表,innoDB设计了rollback segment header页面,在这个页面存放各种链表的第一个页面first undo page的页号,这些页号称为undo slot。可以理解first undo page就是map的key,通过key能找到对应的value,value就是normal undo page。Key会统一管理在rollback segment header里面。

Rollback segment header结构一共16kb:

File header:38个字节。

Trx_rseg_max_Size:4个字节,本rollback segment里管理所有undo链表中undo页面数量之和最大值。换句话说,这里面页面之和不可以超过这个最大值,基本可以默认为无限大。

Trx_rseg_history_Size:4个字节,history链表占用的大小。

Trx_rseg_history:16个字节,history链表的基节点。

Trx_rseg_fseg_header:10个字节,本rollback segment对应10个字节大小的segment header结构,通过他可以找到本段对应的inode entry。

Trx_rseg_undo_slots:4096个字节,存undo链表first undopage 的页号,也就是undo slot集合。(一个页号占用四个字节,对于16kb的页面,这里存着1024个undo slot,所以一共需要1024*4=4096个字节)

File tailder:8个字节。

innoDB规定每个rollback segment header都属于一个段,这个段就是回滚段。与前面介绍段不同的是,这个rollback segment 其实只有一个页面。

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

初始情况下,我们未向任何一个事务分配undo页面链表,所以对于rollback segment header中的各种undo slot都设置成一个特殊值fil_null(表示该undo slot不指向任何页面)。

随着项目的运行,开始有事务申请链表了,从回滚段的第一个开始看是不是fil_null:

如果是fil_null,那么在表空间创建一个新的段(也就是undo log segment),然后从段里申请一个页面作为undo页面链表的first undo page,然后把该undo slot设置为刚刚申请的这个页面的页号,意味着这个undo slot分配给了这个事务。

如果不是fil_null,说明该undo slot已经指向一个链表,也就是说已经被其他事务占用,于是看看下一个undo slot是否是fil_null。

已知rollback segment header有1024个undo slot,如果1024个值都不为fil_null,意味着都分配给了事务,此时无法在获取新的undo页面链表,则就会回滚这个事务给用户报错:

Too many active concurrent transactions

用户看到这个错误,可以重新执行这个事务(因为可能有其他事务已经提交,该事务就可以分配undo链表)。

当一个事务提交时,他所占用的undo slot有两种命运:

  1. 如果该undo slot指向的undo页面链表符合重用(里面只有一个页面,且小于总空间的3/4)

该undo slot就处于被缓存状态,这时候undo链表的trx_undo_state属性会被设置成trx_undo_cache(该属性在first undo page的undo log segment header)。

被缓存的undo slot会加入链表,如果是insert undo会加入insert undo cache链表,如果是update undo会加入update undo cache链表。

一个回滚段就对应着两个cache链表,如果有新事物需要分配undo slot会先去cache链表找,如果没找到,则再去回滚段rollback segment header页面中找。

  1. 如果该undo slot指向undo页面链表不符合被重用的条件,那么针对该undo slot对应的undo页面链表类型不同,会有不同的处理方式:

如果对应的是insert undo 链表,则该undo页面链表的trx_undo_state属性会被设置为trx_undo_to_free,之后该undo页面对应的段会被释放,意味着可以挪做他用,然后把undo slot的值设置为fil_null。

如果对应的是update undo链表,则该undo页面链表的trx_undo_state属性会被设置为trx_undo_to_pruge,之后则会吧undo slot的值设置为fil_null,然后把本次事务写入的一组undo日志放入所谓的history链表中。(注意这里不会释放挪做他用)

多个段回滚

前面说了一个事务最多分配四个undo页面链表,而一个回滚段有1024个undo slot,显示然slot数量有点少。也就是一个回滚段最多容纳1024个读写事务同时执行,再多就崩溃了。因为前面说过rollback unde segment段是固定只有一个页的,不可能一直无线增长。

早期确实只有一个回滚段,但随着业务和机器性能的提升,innoDB一口气定义128个回滚段,相当于128*1024 = 131072个undo slot,那么意思就是支持131072个事务同时执行。

每个回滚段都有一个rollback segment header,所以自然有128个rollback segment header,那么这些自然会统一存起来,于是innoDB在系统空间表第5个页面的某个区域包含了128个8个字节大小的格子,每个格子的构造大概就是:

Space id:4个字节大小,代表表空间的id。

Page number:4个子节大小,代表一个页号。

也就是每8个字节代表一个指针,指向rollback segment header,这里需要注意,不同的segment header对应不同的表空间id。

综上我们知道:系统表空间第五号页面存着128个rollback segment header页面地址,就相当于回滚段。每个回滚段里有1024个undo slot,每个undo slot对应一个undo页面链表。

回滚段分类

回滚段从0开始,吧128个编号的话,第一个就是第0号回滚段,最后一个就是127号回滚段。这128个分为两大类。

第0号、第33~127号属于一类,其中第0号必须在系统表空间,第33~127号既可以咋系统表空间,又可以在undo表空间。(如果一个事务在执行过程中由于对普通表记录做了改动需要分配undo页面链表时,必须从这一类段中分配相对应的undo slot)

第1~32号属于一类。这些必须在临时表空间中(对应的数据目录ibtmp1文件)。

如果一个事务对临时表修改了,则必须从这一类中分配相对应的undo slot。

也就是说两类回滚段一个管理者临时表,一个管理着普通表的undo slot。那么为什么要把普通表和临时表的undo slot分开呢?

因为undo页面本身类型就是fil_page_undo_log的页面简称,说到底他也是个普通的页面。我们前面说够,修改页面之前,一定要先把对应的redo日志写上,这样系统崩溃才能恢复数据。我们在写undo日志本身也是个写页面的过程,所以也会有redo日志记录,防止丢失,innoDB还设计了许多redo日志类型,如mlog_undo_hdr_  cache、mlog_undo_insert、mlog_undo_init等等,也就是说我们对undo页面做任何记录的改动都会记录相对应的redo日志。那么对于临时表,并不需要系统崩溃后恢复,所以临时表的undo日志写入时候,并没有记录redo日志。总结,对于undo日志的记录,会记录redo日志防止系统崩溃数据丢失,而临时表本身就是系统关闭所有数据不需要恢复,所以没有记录redo日志。

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

接下来我们以事务对普通表做改动为例,给大家梳理一下事务执行过程中分配undo页面链表时的完整过程。

  1. 首先事务在执行过程中对普通表做了首次改动,在系统表空间第5号页面中分配回滚段(就是获取一个rollback segment header页面地址)。一旦某个回滚段被分配了这个事务,那么之后该事务对普通表记录做修改,就不会重新分配。

使用传说中的round-robin(循环方式)获取rollback segment header,当第0个回滚段已经分配了事务,则就看第33个回滚段,依次看下一个。

  1. 分配了回滚段后,就要看这里面两个cache链表,如果insert就看insert undo cache链表,如果update 就看update undo cache链表里是否存在undo slot,如果有,则吧undo slot分配给该事务。
  2. 如果没有缓存undo slot,则就去rollback segment header页面找一个可用的undo slot分配给该事务。(前面也说了如果找undo slot,就是从第0个开始,如果不是ful_null,就依次找到1024个ful_null)
  3. 找到undo slot后,如果是缓存中找到的,说明已经分配了undo log segment,如果不是,则需要重新分配undo log segment,然后从undo log segment 申请一个first作为first undo page页面。
  4. 然后事务就可以吧undo日志写入undo页面链表里。

临时表对上亦如此,就不赘述。

回滚段相关配置

配置回滚段数量:

前面说过有128个回滚段,这是个默认值,可以通过innoDB_rollback_segments来配置回滚段,可配置1~128。但这个参数不影响临时回滚段,他一直是32。

也就是说如果这个参数设置为1,临时回滚段还是32.

如果这个参数在2~33之间,普通回滚段还是1.

如果这个参数大于33,则普通回滚段的数量是这个参数减去32的剩余数量。

配置undo表空间:

默认情况下,第0号、第33号到底127号都是在系统表空间。其中0号回滚段一直在系统表空间,但33~127号在自定义undo表空间。可以修改配置,但只能在初始化的时候创建,一旦分配好里面有数据就不能修改。

通过innoDB_undo_directory指定undo表空间所在目录,如果没有指定参数,则默认undo表空间所在目录是数据目录。

通过innoDB_undo_tablespace定义undo表空间数量。该参数默认为0,表明不创建任何undo表空间。

第33~127可以平分分不到不同的undo表空间。

比如我们设置innoDB_rollback_segments的参数是35,innodb_undo_tablespaces的为2,则33,和34号回滚段分布到一个undo表空间中。

设计undo表空间的好处是,会吧undo表空间截取truncate成一个个小文件,而系统表空间大小只会越拉越大。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

重用的undo日志 (3)—mysql进阶(六十六) 的相关文章

  • SQL不允许表中有重复记录

    如何使其不添加重复项 我想让它通过 ID 之外的所有其他列进行检查 我希望这个无效 ID col1 col2 col3 1 first middle last ID col1 col2 col3 2 first middle last 我希
  • POINT 列上的 MySQL INSERT/UPDATE

    我正在尝试用我国家的地理位置填充我的数据库 我的一张表有 4 个字段 ID PK 纬度 经度和地理点 EDIT SCDBs Punto Geografico SET lat 18 469692 SET lon 63 93212 SET g
  • MySQL:计算日期/时间之间的差异 - 仅在周一至周五“工作周”期间

    我需要计算开始日期 时间和结束日期 时间之间的差异 但是 我只想在 5 天的工作周内执行此操作 不包括周六 周日 做这个的最好方式是什么 我的想法是 从日期开始 我必须获取星期几 如果是工作日 那么我将添加到累加器中 如果不是 那么我不会添
  • 在mysql中的单个查询中更新多个表

    我有三个查询 我想要一个 这是我的查询 UPDATE tab1 SET a WHERE id 3 UPDATE tab2 SET b WHERE id 9 UPDATE tab3 SET c WHERE id 5 您可以尝试下面的代码 UP
  • MySql - 复制监控工具[关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我有一个主 从 MySql 复制 我正在寻找一个允许我监视复制的工具 查看它没有错误 检查滞后等 我更喜
  • 如果没有找到值,如何让 MySQL 中的 SUM 函数返回“0”?

    假设我在 MySQL 中有一个简单的函数 SELECT SUM Column 1 FROM Table WHERE Column 2 Test 如果没有条目Column 2 包含文本 Test 然后该函数返回NULL 而我希望它返回 0 我
  • 如何在 MySQL 中求和时间?

    正如您在图片中看到的 我有一份停机报告 显示了所选工厂在选定日期的停机时间 现在我想添加所有的值 Time Duration 列并将其显示在附近的单独显示中 TOTAL TIME DURATION 例如 在图像中 所选日期为 2015 年
  • MySQL 和 Hibernate 之间的主键自增由谁负责?

    MySQL CREATE TABLE role id role INT 11 unsigned NOT NULL AUTO INCREMENT PRIMARY KEY id role AUTO INCREMENT 1 休眠 Entity p
  • mysql转储到derby

    我正在使用 derby 在 eclipse 中进行开发 是否可以从 MySQL 转储表并以某种方式将其用于 derby 我知道 ddl 和 dml 对于两个 dbms 来说是不同的 但我正在寻找一种除了转储 导出之外的合适方法 我可以找到两
  • PHP PDO 使用 bindParam 第一个参数(不带冒号)[重复]

    这个问题在这里已经有答案了 请检查这个 user id int GET user id sql DELETE FROM users WHERE user id user id query db gt prepare sql query gt
  • 每月获取记录,但如果该月没有记录,则为零

    如果我有以下 SQL 表 Tests id type receiveDate 1 Blood 2012 01 18 2 Blood 2012 01 20 3 Blood 2012 01 18 4 Blood 2012 03 01 5 Blo
  • 慢速自动增量重置

    我有很多表 由于某些原因 我需要在应用程序启动时调整这些表的自动增量值 我尝试这样做 mysql gt select max id from item max id 97972232 1 row in set 0 05 sec mysql
  • ORDER BY 字段内的 MySQL 子查询。 (没有内连接)

    有很多与此相关的问题 但都具有使用内部联接的相同答案 这 我认为 在这里是不可能的 如果我错了请告诉我 我现在正在做的是调用两个不同的 mysql 查询来获取结果 它工作完美 db gt query SELECT FROM meta WHE
  • MySQL/PDO::quote() 尽管使用 PDO::PARAM_INT 参数,但仍在整数周围加上引号

    无论我传递给什么值 数据类型对 它都会出现 pdo gt quote value type 它总是将其引用为字符串 echo pdo gt quote foo PDO PARAM STR foo as expected echo pdo g
  • MaxListenersExceededWarning:检测到可能的 EventEmitter 内存泄漏。添加了 11 条消息列表。使用emitter.setMaxListeners()来增加限制

    我知道这可能会标记为重复的解决方案 但堆栈溢出的解决方案对我不起作用 Problem node 5716 MaxListenersExceededWarning Possible EventEmitter memory leak detec
  • 如何检测Mysql/innodb中的死锁?

    我知道在 Innodb 中使用事务时不可避免地会发生死锁 并且如果应用程序代码正确处理死锁 它们是无害的 正如手册所说 只需再试一次 所以我想知道 如何检测死锁 死锁是否会发出一些特殊的 mysql 错误号 如果重要的话 我正在使用 PHP
  • MYSQL从每个类别中随机选择一条记录

    我有一个数据库Items表看起来像这样 id name category int 有几十万条记录 每个item可以是 7 种不同的之一categories 对应于categories table id category 我想要一个从每个类别
  • mysql自动存储记录创建时间戳

    mysql 有什么方法可以在创建记录时自动将时间戳存储在记录行中 我试图使用时间戳 数据类型 和 current timestamp 作为默认值 但后来意识到每次更新记录时都会更新 我只需要一些可以存储创建时间戳的东西 Thanks Set
  • SQL 最近日期

    我需要在 php 中获取诸如 2010 04 27 之类的日期作为字符串 并在表中找到最近的 5 个日期 表中的日期保存为日期类型 您可以使用DATEDIFF http dev mysql com doc refman 5 1 en dat
  • 内部 while 循环不工作

    这是我项目网页上的代码片段 这里我想显示用户选择的类别 然后想显示属于该类别的主题 在那里 用户可以拥有多个类别 这没有问题 我可以在第一个 while 循环中打印所有这些类别 问题是当我尝试打印主题时 结果只显示一行 但每个类别中有更多主

随机推荐

  • FPGA Lattice Diamond 开发环境搭建

    FPGA Lattice Diamond 开发环境搭建 Lattice Diamond 软件下载 在浏览器中输入 Lattice 的官网地址 http www latticesemi com 进入官网首页在上方选择产品系列选项 出现如下图所
  • Unity学习笔记(一)—— 基础知识

    一 基础知识 1 开发团队组成 2 unity特点 图形界面 所见即所得 入门简单 支持C 比OC C 更友好 js 国内外资源丰富 因为使用的人多 跨平台性好 PC端 移动端等 对VR AR的支持最完善 3 成功案例 游戏 炉石传说 神庙
  • 【源码篇】基于ssm+bootstrap+jquery的学生成绩管理系统

    系统介绍 基于ssm bootstrap jquery的学生成绩管理系统一共分为六大模块 分别是用户管理 课程管理 班级管理 学籍管理 学费管理 成绩管理 用户管理 1 用户信息预览 查询并根据姓名搜索系统用户 2 新增用户信息 添加系统用
  • Redis7之事务(五)

    五 Redis 事务 5 1 介绍 可以一次执行多个命令 本质是一组命令的集合 一个事务中的所有命令都会序列化 按顺序地串行化执行而不会被其他命令插入 不许加塞 一个队列中 一次性 顺序性 排他性的执行一系列命令 5 2 Redis事务和数
  • 包管理工具那么多,怎么选?npm、yarn 和 pnpm 三者比较及使用详解!

    1 简介 在 Vue 项目中 我们需要使用许多第三方依赖库 如 Vue Router Vuex Axios Element UI 等等 这些依赖库通常以 NPM 包的形式提供 而且在使用时需要进行版本管理 因此 我们需要使用一个包管理工具来
  • TCP/IP详解 第十二章(2) linux 网络编程

    转载请声明博主https mp csdn net console editor html 106517098 一 Linux网络概述 LINUX网络优势 1 完善的内置网络 和内核结合在一起的网络部分 I p queue 2 Linux 免
  • python将超大CSV文件切割为多个Excel文件存储

    很多时候处理数据会碰到CSV文件 如果是一般的少量文件问题不大 一旦碰到大型的CSV文件 就会出现打不开文件的结果 因为文本无法打开超大型文件 Excel也最多能够容量一百万条数据量 因此只能将CSV文件切割成为多个小的CSV文件 将csv
  • Swing之Jframe窗体、 JDialog弹窗、标签、面板、按钮(图片按钮,单选框,多选框)、列表(下拉框,列表框)、文本框、密码框

    Swing Jframe窗体 import javax swing import java awt public class JFrameDemo init 初始化 public void init JFrame frame new JFr
  • Vue 组件化

    什么是组件化 任何一个人处理信息的逻辑能力都是有限的 所以 当面对一个非常复杂的问题时 我们不太可能一次性搞定一大堆的内容 但是 我们人有一种天生的能力 就是将问题进行拆解 如果将一个复杂的问题 拆分成很多个可以处理的小问题 再将其放在整体
  • 每月的倒扣料

    这是一个生产领料的典型 倒扣法 即BOM配置的单位和发料单位不相同时 我们不可能通过转换而达到发料的方便 比较典型的物料有 电线 按米领料 发料时要按捆化工 按kg领料 发料时按桶等等 通常在实施的时候 先将一捆电线调拔到线边仓库 仓管操作
  • 利用人工智能技术普及教学应用、拓展教师研训应用、增强教育系统监测能力

    2019年 中国教育现代化2035 指出 以人才培养为核心 通过提升校园智能化水平 探索新型教学形式 创新教育服务业态 推进教育治理方式变革 智能驱动教育创新发展 2021年教育部等六部门发布 关于推进教育新型基础设施建设构建高质量教育支撑
  • Linux C/C++编程:对文件操作的封装

    Linux C C 编程 lseek fseek ftell rewind fgetpos fsetpos 源码 Created by oceanstar on 2021 8 9 ifndef OCEANSTAR HTTP ACL FILE
  • 企业网上订货管理软件构架源码系统介绍

    企业网上订货管理软件构架源码系统介绍 手机订单管理系统 一 什么是订货通 什么是企业订货管理系统 是一款针对中小型企业通过网络实现 厂家和客户 经销商 批发商 代理商一站式订货系统 最终实现厂家的下游客户通过网络实现实时订货功能 二 订货通
  • 惊艳了!升级版的 APDrawing,秒让人脸照变线条肖像画

    作者 高卫华 出品 AI科技大本营 随着深度学习的发展 GAN模型在图像风格转换的应用越来越多 其中不少都实现了很好的效果 此前 reddit上的一个技术博主AtreveteTeTe基于GAN模型混合将普通的人像照片卡通化 并通过First
  • AJAX——AJAX的异步与同步、AJAX代码封装

    个人主页 胖虎不秃头 个人简介 Java领域新星创作者 随时准备跑路的大二学生 精品专栏 有这一个就够了 个人名言 知道的越多 不知道的越多 刷题神器 推荐一款算法刷题网站Nowcoder 点击跳转刷题网站进行注册学习 文章目录 AJAX的
  • 可以通过2种方法遍历HashMap

    可以通过2种方法遍历HashMap Map map new HashMap for Iterator iter map entrySet iterator iter hasNext Map Entry entry Map Entry ite
  • 裁剪任意直线段 liang-barshky算法 c

    一 实验目的 使用liang barshky算法实现裁剪任意直线段实验工具 二 实验工具 VC6 0 三 实验步骤 思想 以直线的参数方程为基础 X x1 u x2 x1 Y y1 u y2 y1 裁剪区域是不等式 wxl lt X x1
  • 100天精通Python(可视化篇)——第99天:Pyecharts绘制多种炫酷K线图参数说明+代码实战

    文章目录 专栏导读 一 K线图介绍 1 说明 2 应用场景 二 配置说明 三 K线图实战 1 普通k线图 2 添加辅助线 3 k线图鼠标缩放 4 添加数据缩放滑块 5 K线周期图表 书籍推荐 专栏导读 本文已收录于 100天精通Python
  • linux 积累

    linux文件夹打包命令 tar 解包 tar xvf FileName tar 打包 tar cvf FileName tar DirName 注 tar是打包 不是压缩 gz 解压1 gunzip FileName gz 解压2 gzi
  • 重用的undo日志 (3)—mysql进阶(六十六)

    前面说了undo日志的文件格式 第一页和后面的页是不同的 填入undo日志之前 会先把undo page header属性填满 还有undo segment header undo log header List base node存在un