1. 撤销⽇志在撤销表空间中的组织形式
撤销⽇志在撤销表空间中的组织结构图:
撤销表空间中包含 rollback segments (回滚段),每个回滚段中包含若⼲undoslots(槽数), 每个槽对应⼀个 U ndo log segments (撤销⽇志段),撤销⽇志段中包含具体的撤销⽇志 。
2. 撤销⽇志的格式
撤销⽇志格式⽰意图如下:
⼀条记录在UndoLog⻚中的UndoLog⽇志⼤体包含两部分:分别是记录了Undo类型、表ID、上 ⼀条、下⼀条⽇志的偏移地址等在内的"基本信息",以及记录了不同操作和数据的"操作信息"。
在执⾏DML语句操作数据库时,不同SQL语句对应的撤销操作不同,不同的撤销操作对应的Undo Log存储格式也不相同,按照增、删、改等不同的DML操作,⽣成对应的撤销⽇志。
不同操作对应的撤销⽇志区分:
3. 撤销⽇志是如何组织在⼀起的?
撤销⽇志的组织⽰意图如下:
4. 撤销⽇志如何分类
为了方便管理日志进行分类:
InnoDB最⼤⽀持并发读写事务的数量如何计算 :
5. 如何理解Undo链
6. 撤销⽇志为需要落盘的原因
• 在对数据进⾏修改时,都是在内存中操作的,也就是在BufferPool中修改对应的数据⻚,在修改数 据⻚之前先把对应的撤销⽇志记录在内存中,如果此时事务回滚直接根据内存中的撤销⽇志做回滚 操作即可;
• 在修改完成提交事务后,脏⻚进⾏落盘操作,此时事务已提交,不能回滚,所以撤销⽇志也就失效 了;
• 当服务器崩溃时,如果事务没有提交,所有的修改都在内存中,还没有落盘,对于修改直接丢弃; 如果事务已经提交,则根据重做⽇志和双写缓冲区中的备份进⾏恢复;
• 通过分析看上去撤销⽇志并不需要落盘,其实以上的分析场景并没有考虑到全部的场景,⽐如⼤事 务的运⾏、MVCC中版本链什么时候可以销毁、事务的不同隔离级别等因素;
UndoLog落盘必须在真实数据落盘之前。
• 在运⾏⼤事务时,InnoDB为了避免⼤事务提交时统⼀落盘操作带来的性能问题,允许在事务进⾏ 的过程中就进⾏落盘操作并记录对应的UndoLog,当发⽣崩溃恢复时,通过回放UndoLog把未提 交的事务进⾏回滚;
• 如果⼀个事务已经提交,但还有其他事务需要访问版本链中对应的UndoLog,那么也需要把相应的 撤销⽇志保存到 hisotry list 中。
• 不同隔离级别下,没有提交的事务也可能会落盘,回滚时依然要完成撤销操作
撤销⽇志在内存中如何记录:
7. 双写缓冲区-DoublewriteBuffer
作用:• 双写缓冲区是磁盘上的⼀个存储区域,当 InnoDB 将缓冲池中的数据⻚写⼊到磁盘上表空间数据 ⽂件之前,先将对应的⻚写到双写缓冲区;如果在数据真正落盘的过程中出现了意外退出,⽐如操 作系统、存储⼦系统崩溃或异常断电的情况, InnoDB 在崩溃恢复时可以从双写缓冲区中找到⼀ 份完好的⻚副本,执⾏过程如下图所⽰:
双写缓冲区中的数据保存位置:
如何配置双写缓冲区 :
是否启⽤ doublewrite 缓冲区可以通过系统变量 innodb_doublewrite[=ON|OFF] 控制, 默认为启⽤,如果真实的业务场景更关注性能⽽不是数据完整性,可以考虑禁⽤doublewrite缓冲 区,例如在执⾏测试的环境中;
• d oublewrite ⽂件所在⽬录通过系统变量 innodb_doublewrite_dir (MySQL8.0.20中引 ⼊)指定,如果不指定则在 innodb_data_home_dir ⽬录(默认为data⽬录)下创建;如果指定 doublewrite⽬录,建议设置在最快的存储介质上,以提⾼效率;
双写⽂件的数量通过系统变量 #ib_16384_0.dblwr 的⽂件 innodb_doublewrite_files 设置,默认情况下,为每个缓冲 池实例创建两个doublewrite⽂件,也就是说⽂件数量为 innodb_buffer_pool_instances * 2 ;此变量⽤于⾼级性能调优,⼤多数场景使⽤默认设置即可;
8. 重做⽇志-RedoLog
重做⽇志的作⽤:
重做⽇志在保证事务的持久性和⼀致性⽅⾯起到了⾄关重要的作⽤
• 重做⽇志⽤于在数据库崩溃后恢复已提交事务还没有来的及落盘的数据。重做⽇志以⽂件的形式保 存在磁盘上,在正常的操作过程中,MySQL根据受影响的记录进⾏编码并写⼊重做⽇志⽂件,这些 数据称为"Redo",在重新启动时⾃动读取重做⽇志进⾏数据恢复。
为什么要⽤RedoLog,⽽不是直接写磁盘?
• ⾸先,我们对数据进⾏的DML操作都会包含在事务当中,当完成修改并 且提交事务之后,在内存中被修改的数据⻚就要刷新到磁盘完成持久化;
• 那么如果这次DML操作对应的修改开始刷盘的话,当服务器崩溃,没有被刷到磁盘的数据⻚就从内 存中丢失,这时这个事务的修改在磁盘上就是不完整的,也就是没有保证事务的⼀致性
• 为了解决这个问题,InnoDB在执⾏每个DML操作时,当内存中的数据⻚修改完成之后,把修改的 内容以⽇志的形式保证在磁盘上,然后再对数据⻚进⾏真正的落盘操作,这样做就相当于对修改进 ⾏了⼀次备份,即使当服务器崩溃也不会受到影响,当服务器重启之后,可以从磁盘上的⽇志⽂件 中找到上次崩溃之前没有来的及落盘的数据继续执⾏落盘操作;
• InnoDB引擎的事务采⽤了 WAL 技术 (Write-Ahead Logging) ,基本思想是先写⽇志,再写磁 盘,只有⽇志写⼊成功,事务才算提交成功,这⾥的⽇志就是RedoLog。当发⽣宕机且数据未刷到 磁盘的时候,可以通过RedoLog来恢复,保证ACID中的持久性,这也是RedoLog的作⽤。
undo日志保证了事务的原子性,redo日志保证了事务的持久性。
Redo Log的写⼊时机?
• 当发⽣数据修改操作时追加重做⽇志,已落盘数据对应的⽇志位置被记录为⼀个检查点,检查点之 前的数据被置为⽆效,所以重做⽇志⽂件可以循环使⽤。以⼀个更新操作为例,重做⽇志的写⼊过 程与时机,如下图所⽰:
至于使用到LogBuffer,因为每次进⾏DML操作都会进⾏⼀次磁盘I/O,这样会严 重影响效率,所以把⽇志统⼀写⼊内存中的LogBuffer,根据刷盘策略统⼀进⾏落盘操作,可以实 现⼀次磁盘I/O写⼊多条⽇志,从⽽提升效率。
9. RedoLog的格式
• 当进⾏DML操作时,⾸先要修改内存中的数据⻚,但是修改的数据有可能只是数据⻚中很少的⼀部 分内容,甚⾄有可能只修改了⼏个字节,那么在RedoLog中是要记录整个数据⻚吗?当然不是,如 果每次保存整个数据⻚的话就有太多的⽆⽤数据写⼊⽇志,严重影响效率⽽且浪费空间
• 为了节省空间提⾼效率,RedoLog只记录被修改的内容,⽐如当前的DML修改了哪个表空间、表空 间中的哪个数据⻚,数据⻚中多少偏移量处的值修改成了什么,⽐如:
10. RedoLog的类型
• RedoLog的类型根据数据操作的不同场景和对⽇志的优化⽅式有⼏⼗种之多,总体可以分为:
◦ ⽤于数据⻚的⽇志类型,⽐如对数据⻚的修改
◦ ⽤于表空间⽂件的⽇志类型,⽐如对表空间的修改
◦ 提供额外信息的⽇志类型
不同⽇志类型对应了哪些操作:
不同的⽇志类型对应的⽇志内容和作⽤各不相同,
• ⽤于数据⻚的⽇志类型 主要记录数据⻚的修改,⽐如创建和删除数据⻚,以及对数据的增删改查操作
• ⽤于表空间⽂件的⽇志类型 主要记录对表空间⽂件的修改
• 提供额外信息的⽇志类型 主要标记⼀个Mini-Transaction的结尾
如果⼀个DML操作修改了表中的多个字段,⽇志如何表⽰?
通常情况下,⼀个DML操作会修改表中的多个字 段,也可能修改多条记录,对于正常的增删改对应不同的⽇志类型,对应⽇志所包含的主要信息如下图所⽰:
• 新增操作:主要包含数据⻚内的偏移量,主键信息,新增的字段个数,每个字段的内容的实际⻓ 度,具体的内容等
• 删除操作:主要包含数据⻚内的偏移量,主键信息、旧事务的Id,旧roll_pointer,是否删除标识
• 更新操作:主要包含数据⻚内的偏移量,主键信息、旧事务的Id,旧roll_pointer,被更新字段的 数据,每个被更新字段的实际⻓度,更新的具体内容
11 Mini-Transaction
q1:DML操作会对数据⻚产⽣什么样的影响?
• 以⼀个Insert操作为例,对数据⻚的影响⼀般分为两种情况:
◦ 如果写⼊记录所在的数据⻚空间充⾜,⾜够存储⼀条将要写⼊的记录,那么就可以直接写⼊, 如下图所⽰:
如果写⼊的数据⻚空间不充⾜,⽆法放下这条记录,由于在数据⻚中真实数据是按主键顺序排 列的,那么就要新建⼀个数据⻚,对原来的数据进⾏调整,把⼀部分数据复制到新的数据⻚ 中,以便在⽬标数据⻚上留出⾜够的空间来保存即将写⼊的记录,此时对应的⽰意图如下所⽰:
通过以上两种情况下插⼊⼀条记录的分析可以看出,当数据⻚空间充⾜的情况下可以直接写⼊数 据,并记录⼀条对应RedoLog即可
• 当数据⻚空间不充⾜⽆法放下这条记录的情况下,会创建⼀个新数据⻚,同时还有数据的复制和写 ⼊,索引树⾮叶⼦节点上修改,在实际的执⾏过程中还有对表空间中段、区中统计信息的修改等 等,这意味⼀个简单的Insert操作有会产⽣很多条RedoLog。
如果执⾏这⼀系统操作的时候,RedoLog只记录了⼀半服 务器就崩溃了,那么当服务器重启的时候如果按照RedoLog进⾏恢复,得到的结果肯定是错误的, 所以在记录RedoLog的时候要保证⼀个DML所对应的⼀系列⽇志必须是完整的才可以执⾏恢复操 作,否则就不执⾏恢复。 所以我们就引入了Mini-Transaction。
Mini-Transaction的定义
• Mini-Transaction是MySQL内部对底层数据⻚的⼀个原⼦操作,包含⼀个DML操作产⽣的⼀组完整 ⽇志,保证数据库异常恢复时数据⻚中数据的⼀致性。
如何标识⼀组RedoLog属于同⼀个MTR?
• 在执⾏DML操作的过程中,每⼀个对数据⻚的修改都会记录⼀条RedoLog,这些⽇志会被顺序记录 下来,并在这组⽇志的最后加⼀条特殊的⽇志标识作为⼀个MRT的结尾,这条特殊的⽇志结构⾮常 简单,只有⼀个 TYPE 字段,类型为 MLOG_MULTI_REC_END = 31 ,也就是⽇志分类中的提 供额外信息的⽇志类型,⼀个MTR对应的⽇志组,如下图所⽰:
如果⼀个MTR中只有⼀条⽇志是否可以优化?
• 当然可以,如果⼀个MTR只有⼀条⽇志,直接在这条⽇志后加⼀个类型为 MLOG_MULTI_REC_END = 31 的标识可以做为MTR的结尾,但这样做有点浪费空间;
• InnoDB为了尽可能的节省空间,在MTR只有⼀条⽇志的情况下,做了⼀个优化。通过上⾯的介绍 了解了⽇志类型虽然很多,但也只有⼏⼗种,⽽⽤来表⽰⽇志类型的 ⽽这 1 TYPE 字段⻓度为 1BTYE , BTYE 中只⽤7个⽐特位,代表整数127,就完全可以表⽰所有的⽇志类型,与是省出来⼀个 ⽐特位就可以⽤来表⽰当前MTR包含⼀条还是⼀组RedoLog,也就是说如果 TYPE 字段的第⼀个 ⽐特位为 1 ,表⽰MTR只包含⼀条RedoLog,为 0 表⽰MTR包含⼀组RedoLog,如下图所⽰:
事务与Mini-Transaction的关系
• Mini-Transaction是包含的是⼀个DML操作对应的⼀组RedoLog,⽽⼀个事务中可能会包含多个 DML操作,所以⼀个事务中包含⼀个或多个SQL语句,⼀个SQL语句包含⼀个或多个MRT,⼀个 MTR包含⼀条或多条RedoLog,他们之间的关系如下图所⽰:
12 RedoLog的是如何写⼊缓冲区的
Log Block Header 和 Log Block Trailer 包含的信息如下图所⽰:
Redo LogBlock在LogBuffer中的如何组织方式
• 在内存中RedoLog存储在⽇志缓冲区(LogBuffer)中,⽇志缓冲区是服务器启动时向操作系统申请 的⼀⽚连续的内存区域,并被划分成若⼲个连续的 Redo Log Block ,⽤来存储即将要写⼊磁 盘⽇志⽂件的数据,如下图所⽰:
InnoDB 的提供了⼀个名为 buf_free 的全局变量,该变量表⽰后续写⼊⽇志在 Log Buffer 中的起始位置,如图所⽰:
不同的事务在并发执⾏时如何记录RedoLog
• 通过前⾯的介绍了解到,InnoDB以MTR为单位记录RedoLog,⼀个事务中包含多个MTR,⼀个 MTR包含多条RedoLog,这些RedoLog是⼀个不可分割的⽇志组;
• ⼀个事务在执⾏过程中并不是每⽣成⼀条RedoLog就写⼊到LogBuffer中,⽽是把⽣成的RedoLog 先缓存在内存的⼀个区域中,当⼀个MTR执⾏完成后把这组⽇志⼀起复制到LogBuffer;
• 假设有两个事务T1,T2并发执⾏,每个事务中都包含2个MRT,即事务T1包含mtr_t1_1和 mtr_t1_2,T2包含mtr_t2_1和mtr_t2_2,如下图所⽰:
在并发环境下不同事务中的MTR是交替执⾏的,当MTR执⾏完成之后对应⽣成的RedoLog会被写⼊ LogBuffer, 所以在LogBuffer中⽇志的写⼊形式如下图所⽰:
13.RedoLog的刷盘时机
当⼀个MTR执⾏完成后,RedoLog会被写⼊LogBuffer,⽽LogBuffer⼤⼩是有限的,并且这些记 录⽇志的⽬的是为了服务器崩溃后的数据恢复,在内存中保存也不安全,所以在把它们刷到磁盘上 进⾏保存
刷盘策略进⾏配置:
不同的刷盘策略的影响
LogBuffer、操作系统缓存和磁盘中⽇志⽂件的关系,如图所⽰:
14 RedoLog对应磁盘上的⽂件
这么多⽇志⽂件⽇志写到哪个⽂件中
• 通过查看 #innodb_redo ⽬录,可以看到系统⽣成了32个RedoLog⽂件,当RedoLog从内存刷 到磁盘时,先从第⼀个⽇志⽂件开始写,第⼀个写满之后顺序写到第⼆个,以此类推;如果最后⼀ 个也写满了,就会重新从第⼀个⽂件开始写,也就是说重做⽇志⽂件可以循环使⽤,如图所⽰:
关于LSN
15 RedoLog⽇志⽂件的格式
重做⽇志⽂件管理区包含哪些信息:
管理区中具体管理了什么信息:
什么是CHECKPOINT-检查点
哪些RedoLog可以被覆盖
经过分析可以看出,判断⽇志⽂件中的RedoLog是否可以覆盖的依据是它对应的数据⻚是否已经刷 新到磁盘。
如何记录可以覆盖的⽇志⽂件位置:
16 重做⽇志还有哪些主要的配置项
如何查看重做⽇志的状态?
• 通过状态变量 innodb_redo_log_capacity_resized 显⽰当前重做⽇志容量限制
17 如何根据RedoLog进⾏崩溃恢复
18 通⽤表空间-GeneralTablespace
通⽤表空间的作⽤和特性:
怎么创建通⽤表空间:
创建通⽤表空间的⽰例:
创建通⽤表空间时要注意什么:
如何向通⽤表空间中添加表:
向通⽤表空间中添加表,在创建表时使⽤ TABLESPACE ⼦句指定通⽤表空间即可
怎么删除通⽤表空间:
使⽤通⽤表空间时要注意什么
• 使⽤ TRUNCATE 或 DROP 语句截断或删除表时,通⽤表空间的空闲容量并不会释放,并且只能⽤ 于新的InnoDB表;
• 通⽤表空间不属于任何数据库,使⽤ DROP DATABASE 操作数据库和属于该数据库所有的表时, 并不会删除通⽤表空间。
• t ablespace_name 表空间名区分⼤⼩写
19 临时表空间-TemporaryTablespaces
临时表存储的是临时数据,不能永久的存储数据,⼀般在复杂的查询或计算过程中⽤来存储过渡的 中间结果,MySQL在执⾏查询与计算的过程中会⾃动⽣成临时表,⽐如表连接查询时得到的结果集 就是⼀张临时表,因为结果中可能包含多个表中的字段并没有⼀张真实的表与之完全对应。
一般在进行多表联合查询的过程中,会通过临时表来进行结果查找的过度。
外部临时表 :
什么是内部临时表:
即• 由服务器⾃动创建的临时表是内部临时表,通常MySQL在执⾏查询与计算的过程中会⾃动⽣成的内 部临时表
20 临时表都有的设置
通过配置对应的系统变量来指定临时表使⽤的存储引擎、使⽤内存的⼤⼩、表中的最⼤⾏数等选 项。
临时表中的数据存储文件:
全局临时表空间的作⽤?
• 全局临时表空间存储对⽤⼾创建的临时表所做的更改,以便以后回滚操作,类似于nudo表空间,记录的是临时表的回滚日志。
查看全局临时表空间的信息和⼤⼩
ps:学习mysql是仅用于笔记整理方便复习。