wordpress 酒店预定seo外链怎么做能看到效果
- 作者: 多梦笔记
- 时间: 2026年02月18日 13:07
当前位置: 首页 > news >正文
wordpress 酒店预定,seo外链怎么做能看到效果,手机如做网站,品牌标志logo大全InnoDB 磁盘⽂件 1 InnoDB存储引擎包含哪些磁盘⽂件#xff1f; #x1f50d; 分析过程 ✅ 解答问题 InnoDB的磁盘⽂件主要是表空间⽂件和其他⽂件#xff0c;表空间包括#xff1a;系统表空间、独⽴表空间、通⽤表空间、临时表空间和撤销表空间#xff1b;其他⽂件有重做…InnoDB 磁盘⽂件 1 InnoDB存储引擎包含哪些磁盘⽂件 分析过程 ✅ 解答问题 InnoDB的磁盘⽂件主要是表空间⽂件和其他⽂件表空间包括系统表空间、独⽴表空间、通⽤表空间、临时表空间和撤销表空间其他⽂件有重做⽇志和双写缓冲区 1.1 什么是表空间 表空间可以理解为MYSQL为了管理数据⽽设计的⼀种数据结构主要描述的对结构的定义表空间⽂件是对定义的具体实现以⽂件的形式存在于磁盘上以后我们说的表空间指的就是表空间⽂件InnoDB存储引擎的表空间包括系统表空间、独⽴表空间、通⽤表空间、临时表空间和撤销表空间 4 系统表空间 - System Tablespace 4.1 系统表空间的作⽤ ✅ 解答问题 系统表空间存储了MySQL中所有系统表的数据也包括数据字典系统表空间也是变更缓冲区的存储区域当数据库服务器关闭时没有合并到缓冲池的⼆级索引修改操作被保存到系统表空间在以前的版本中系统表空间也包含双写缓冲区从MySQL 8.0.20开始双写缓冲区从系统表空间中移到单独的⽂件中。 4.2 系统表空间⽂件保存在哪⾥ 系统表空间可以对应⼀个或多个数据⽂件默认情况下MySQL在 data ⽬录中创建⼀个系统表空间数据⽂件 ibdata1 。系统表空间数据⽂件的⼤⼩和数量由 innodb_data_file_path 启动选项定义。 4.3 系统表空间都有哪些可以配置的选项 分析过程 可以通过 innodb_data_file_path 选项定义如果没有指定 innodb_data_file_path 的值则默认创建⼀个⼤⼩可以⾃动扩展的数据⽂件⽂件名为 ibdata1 初始⼤⼩ 12MB 。 数据⽂件命名规范的完整语法包括⽂件名、⽂件⼤⼩、⾃动扩展属性和max属性: file_name:file_size[:autoextend[:max:max_file_size]] 通过在 file_size 值后⾯指定单位 K 、 M 或 G 来设置⽂件⼤⼩单位为 千字节 、 兆字节 或 千兆字节 。如果以 K 为单位指定⽂件⼤⼩应设置为1024的倍数。否则千字节值四舍五⼊到最接近的兆字节 (MB) 且⽂件⼤⼩⾄少为 12MB 。 指定多个数据⽂件可以使⽤分号 ; 分隔。例如: autoextend 和 max 属性只能⽤于最后指定的数据⽂件当指定 autoextend 属性时数据⽂件的⼤⼩会根据需要⾃动扩容默认每次增加 64MB 。可以通过系统变量innodb_autoextend_increment 控制增量的⼤⼩如果要指定数据⽂件的最⼤容量在autoextend 后⾯指定 max 属性。注意只有在明确了解限制磁盘使⽤的情况下才使⽤ max 属性。下⾯的配置允许 ibdata1 扩展到 500MB : 系统表空间⽂件默认创建在 data ⽬录下。如果指定其他的⽬录使⽤innodb_data_home_dir 选项。例如要在名为 myibdata 的⽬录下创建⼀个系统表空间数据⽂件可以使⽤如下配置: 注意指定 innodb_data_home_dir 时必须以斜杠 / 结尾InnoDB不会⾃动创建⽬录所以在启动服务器之前要确保指定的⽬录已经存在最终通过 innodb_data_home_dir 指定的路径与数据⽂件名组合起来⽣成完整路径如果 innodb_data_home_dir 不指定默认值为 ./ 即MySQL的数据⽬录 如果 innodb_data_file_path 指定⼀个绝对路径则不会读取 innodb_data_home_dir 的值系统表空间⽂件根据指定的绝对路径创建启动服务器之前必须确保指定的⽬录存在。在添加新的数据⽂件时不要指定现有的⽂件名InnoDB在启动服务器时会创建并初始化新的数据⽂件。 ✅ 解答问题 根据实际应⽤场景通过配置对应的系统变量来指定数据⽂件的⼤⼩、名称、数量和其他属性。 4.4 修改系统表空间配置后什么时候⽣效 在修改系统表空间配置时先停⽌MySQL服务修改完成后再重新启动MySQL服务之后⽣效。 5 独⽴表空间 - File-Per-Table Tablespace 5.1 独⽴表空间的作⽤ ✅ 解答问题 File-Per-Table 表空间包含单个InnoDB表的数据和索引默认情况下每张表都对应⼀个表空间数据⽂件便于维护所以称为 File-Per-Table Tablespace 5.2 独⽴表空间⽂件保存在哪⾥ File-Per-Table 表空间在 data/database_name/ ⽬录下的 table_name.ibd 表空间数据⽂件中创建。 .ibd ⽂件与表同名。例如表 test_db.t1 的数据⽂件如下所⽰ 查看数据⽂件 5.3 每个表都对应⼀个独⽴表空间吗 默认每张表都对应⼀个表空间数据⽂件但也可以通过系统变量 innodb_file_per_table[{OFF|ON}] 控制开启或禁⽤是否为每张表⽣成⼀个独⽴表空间⽂件如果禁⽤会在系统表空间中创建表可以在选项⽂件中指定 innodb_file_per_table 设置也可以在运⾏时使⽤ SET GLOBAL语句设置 5.4 独⽴表空间的优点和缺点 ✅ 解答问题 优点 使⽤ TRUNCATE 或 DROP 语句删除 File-Per-Table 表空间中的表后磁盘空间会返回给操作系统从⽽提⾼磁盘利⽤率⽽共享表空间(⽐如 System Tablespace )则不会回收磁盘空间⽽且在共享表空间中这些空间只能被InnoDB表重新使⽤执⾏时 TRUNCATE TABLE 时性能更好可以在其他⽬录或单独的存储设备上创建 File-Per-Table 表空间⽂件的数据⽂件从⽽达到I/O优化、空间管理或备份的⽬的
指定DATA directory⼦句可以在外部⽬录中创建表
CREATE TABLE t1 (c1 INT PRIMARY KEY) DATA DIRECTORY /external/directory;⽀持与 DYNAMIC 和 COMPRESSED ⾏格式⽽系统表空间不⽀持发⽣数据损坏、备份、⼆进制⽇志不可⽤或MySQL服务器实例⽆法重新启动时提⾼成功恢复的机会单个表容量⼤⼩限制为 64TB 所以可以存储更多的数据⽽共享表空间中的表的总容量为64TB 。 缺点 每个表都可能有未使⽤的空间这些空间只能由对应的表使⽤如果管理不当可能会导致空间浪费当每个表都有⾃⼰的数据⽂件操作系统需要维护更多的⽂件描述符如果表⾮常多可能会影响性能可能会出现更多的磁盘碎⽚会影响 DROP TABLE 表扫描性能innodb_autoextend_increment 系统变量定义了⾃动扩展共享表空间⽂件的增量⼤⼩但对于 File-Per-Table 表空间⽂件不起作⽤ File-Per-Table 表空间⽂件始终⾃动扩展初始⼤⼩根据表定义分配最⼩的空间之后以 4MB 为增量进⾏扩容。 6 撤销表空间 - Undo Tablespaces 6.1 撤销表空间的作⽤ ✅ 解答问题 撤销表空间中包含撤销⽇志(Undo Log)撤销⽇志记录了如何撤销事务对聚集索引记录的最新更改(事务的回滚)通过对事务的回滚从⽽保证事务ACID特性中的原⼦性。 6.2 在使⽤MySQL时并没有⼿动创建撤销表空间它是什么时候被创建的 分析过程 MySQL初始化时会在数据⽬录下创建两个默认的撤销表空间数据⽂件名分别为 undo_001 和undo_002 数据字典中对应undo表空间名称为 innodb_undo_001 和innodb_undo_002 ✅ 解答问题 MySQL初始化时会在数据⽬录下创建两个默认的撤销表空间数据⽂件名分别为 undo_001 和 undo_002 6.2.1 默认的撤销表空间名称和路径是什么 要查看撤销表空间名称和路径请查询 INFORMATION_SCHEMA.FILES 6.3 可以⼿动创建撤销表空间吗 可以通过使⽤ CREATE UNDO TABLESPACE 语句可以创建撤销表空间 6.3.1 什么时候需要⼿动创建撤销表空间 对于⻓时间运⾏的⼤事务撤销⽇志可能会变得很⼤通过创建额外的撤销表空间来防⽌单个撤销表空间变得太⼤从 MySQL 8.0.14 开始可以在运⾏时使⽤ CREATE UNDO TABLESPACE 语法创建额外的撤销表空间 6.3.2 使⽤⾃⼰创建的撤销表空间需要注意什么 通过系统变量 innodb_undo_directory 指定撤销表空间的默认存放路径如果不指定默认位置为数据⽬录撤销表空间⽂件名必须以 .ibu 为扩展名定义undo表空间⽂件名时如果需要指定路径必须使⽤绝对路径不允许指定相对路径建议使⽤唯⼀的撤销表空间⽂件名避免在以后移动和复制的过程中发⽣⽂件名冲突如果指定其他路径那么路径必须在 innodb_directories 中定义以便MySQL扫描并识别最多⽀持 127 个 undo 表空间包括实例初始化时创建的两个默认表空间MySQL 8.0.23 开始初始撤销表空间⼤⼩通常为 16MB并根据服务器负载以 [16MB, 256MB] 的增量进⾏扩容 MySQL 8.0.14 之前版本额外的撤销表空间通过配置系统变量 innodb_undo_tablespaces 来创建取值范围[2, 127]MySQL 8.0.14 开始此变量已弃⽤且不再可配置。 6.4 如何删除撤销表空间 分析过程 从 MySQL 8.0.14开始使⽤ CREATE UNDO TABLESPACE 语法创建的撤销表空间可以使⽤DROP UNDO TABALESPAC 语法删除撤销表空间在被删除之前必须是空的要清空撤销表空间必须⾸先使⽤ ALTER UNDO TABLESPACE 语法将撤销表空间标记为不活动以便该表空间不再⽤于其他新的事务
语法
ALTER UNDO TABLESPACE tablespace_name SET INACTIVE;在将undo表空间标记为⾮活动后等待当前undo表空间的事务完成后表空间被截断到初始⼤⼩当undo表空间为空就可以进⾏删除操作
语法
DROP UNDO TABLESPACE tablespace_name;✅ 解答问题 从 MySQL 8.0.14开始使⽤ CREATE UNDO TABLESPACE 语法创建的撤销表空间可以使⽤DROP UNDO TABALESPAC 语法删除但要确保撤销表空间在被删除之前必须是空的具体的操作步骤如下 将撤销表空间标记为不活动等待当前undo表空间的事务完成后表空间被截断到初始⼤⼩执⾏删除操作
6.4.1 删除撤销表空间的⽰例 6.4.2 撤销表空间被置为不活动并且已被截断为初始⼤⼩这时不想删除了是否可以重新启⽤
undo表空间状态为空时可以重新激活⽅法如下
语法
ALTER undo tablespace tablespace_name SET ACTIVE;6.5 如何查看撤销表空间的状态 ✅ 解答问题 通过 SHOW STATUS LIKE ‘Innodb_undo_tablespaces%’; 语句可以查看撤销表空间的基本信息 7 撤销⽇志 - Undo Log 7.1 什么是撤销⽇志 ✅ 解答问题 当事务对数据进⾏修改的时候每个修改操作都会在磁盘上创建与之对应的Undo Log当事务需要回滚时会根据Undo Log逐⼀进⾏撤销操作从⽽保证事务的原⼦性。也就是说撤销⽇志是为事务的回滚操作⽽诞⽣的机制它是⼀个撤销操作记录的集合.Undo⽇志保存在Undo⽇志段中Undo⽇志段位于回滚段中回滚段位于undo表空间和全局临时表空间中。 7.1.1 撤销⽇志的写⼊时机 在事务执⾏每个DML之前会根据DML构建对应的撤销⽇志并申请⼀个 undo log segments (撤销⽇志段)把⽇志记录在申请到的撤销段中再执⾏真正的DML操作执⾏过程如下所⽰ 7.2 撤销⽇志在撤销表空间中的组织形式是怎样的 分析过程 ⾸先看来撤销⽇志在撤销表空间中的组织结构图如下所⽰ Undo log segments (撤销⽇志段)也称为撤销段⼀个撤销⽇志段可以保存多个事务的回滚⽇志但在同⼀时间只能被⼀个活跃事务使⽤对应的空间在事务提交或回滚后才可以被重⽤。rollback segments (回滚段)中包含撤销⽇志段通常位于undo表空间和全局临时表空间中使⽤系统变量 Innodb_rollback_segments 可以定义分配给每个undo表空间和全局临时表空间的回滚段的数量默认值为128取值范围是[1, 128]⼀个回滚段⽀持的事务数取决于回滚段中的undo slots(槽数)和每个事务所需的undo⽇志数⼀个回滚段中的undo槽数可以根据InnoDB⻚⾯⼤⼩进⾏计算公式是(InnoDB Page Size / 16)⽐如默认情况下 InnoDB Page Size ⼤⼩为 16KB 那么⼀个回滚段就可以包含 1024 个 undo slot ⽤来存储事务的撤销⽇志。回滚段中还记录了 History List 的头节点 History List Base Node 以及回滚段的⼤⼩通过系统变量 innodb_rollback_segments 可以设置Undo表空间中的回滚段数量最⼤值和默认值都是128
查看Undo表空间中的回滚段数量
mysql show variables like innodb_rollback_segments;✅ 解答问题 撤销表空间中包含 rollback segments (回滚段)每个回滚段中包含若⼲undo slots(槽数)每个槽对应⼀个 Undo log segments (撤销⽇志段)撤销⽇志段中包含具体的撤销⽇志
7.3 撤销⽇志的格式是怎样的 分析过程 撤销⽇志格式⽰意图如下 ✅ 解答问题 ⼀条记录在Undo Log⻚中的Undo Log⽇志⼤体包含两部分分别是记录了Undo类型、表ID、上⼀条、下⼀条⽇志的偏移地址等在内的基本信息以及记录了不同操作和数据的操作信息如上图所⽰
7.3.1 在事务中不同的DML操作对应的撤销⽇志是否不同
在执⾏DML语句操作数据库时不同SQL语句对应的撤销操作不同不同的撤销操作对应的UndoLog存储格式也不相同按照增、删、改等不同的DML操作⽣成对应的撤销⽇志。
7.3.2 不同操作对应的撤销⽇志如何区分
Undo类型有很多种最常⻅的就是增、删、改分别⽤ TRX_UNDO_INSERT_REC 、TRX_UNDO_DEL_MARK_REC 和 TRX_UNDO_UPD_EXIST_REC 表⽰如图所⽰ 新增( TRX_UNDO_INSERT_REC )时的Undo Log操作信息相对简单只记录了主键值主键⻓度等主键信息删除( TRX_UNDO_DEL_MARK_REC )时除了记录主键信息之外还记录了旧的事务ID旧的ROLL_POINTER信息⽤来构建有序的Undo版本链还会记录⼀些被索引字段的信息更新( TRX_UNDO_UPD_EXIST_REC )时较为复杂如果不更新主键则和删除时类似会记录主键信息、旧的事务ID、旧的ROLL_POINTER信息、被索引字段的信息和被更新的信息如果更新了主键则会记录两条Undo Log ⼀条删除的和⼀条新增的 7.4 撤销⽇志是如何组织在⼀起的 分析过程 撤销⽇志的组织⽰意图如下 ✅ 解答问题 ⼀条条Undo Log会被逐⼀放在Undo Log⻚中Undo Log⻚和其他类型的⻚⼀样都会包含头尾信息除此之外还有Undo Log特有的信息包括 UNDO PAGE HEADER 记录了Undo Log⻚类型、⽇志偏移位置、下⼀⻚链表引⽤等信息UNDO LOG SEGMENT HEADER 记录了回滚段信息UNDO LOG HEADER 记录了产⽣这条⽇志的事务IdTrx ID事务的提交顺序Trx No和其他事务相关信息 在这三个特有的头信息之外其他空间都会⽤来记录Undo Log⽇志如果某个事务很⼤⼀个Undo Log⻚没有办法完整记录就需要申请新的Undo Log⻚然后通过 UNDO PAGE HEADER 中链表引⽤信息链接到前⼀个⻚后⾯的这些⻚只需要记录Undo Log并不需要记录Undo头信息。这个由Undo Log构成的链表称做Undo链在事务中会起到⾮常重要的作⽤。
7.4.1 事务提交后Undo Log是否就可以删除了
这⾥强调⼀下对于新增操作所记录的Undo Log⽇志在事务提交之后就可以直接删除了⽽删除和更新的Undo Log⽇志还需要服务事务的MVCC所以并不能直接删除⽽是加⼊到hisotry list 中。因些InnoDB为了最⼤程度节省空间提升效率对Undo Log进⾏了分类
7.5 撤销⽇志如何分类 ✅ 解答问题 Undo Log分为两⼤类⼀类只记录新增操作事务提交后可以直接清除另⼀类记录删除和更新操作所以相应的回滚链也会被区分为2个Insert Undo链 和 Update Undo链(Delete Update)另外普通表和临时表分别对应这两类Undo链如是⼀个事务既有新增⼜有修改并且⽤到了临时表那么这个事务最多可以分配四个撤销⽇志也就是四个Undo链分别是 对⽤⼾定义的普通表进⾏ INSERT 操作对⽤⼾定义的普通表进⾏ UPDATE 和 DELETE 操作对⽤⼾定义的临时表进⾏ INSERT 操作对⽤⼾定义的临时表进⾏ UPDATE 和 DELETE 操作 根据事务的操作按需要写⼊Undo⽇志⽐如在普通表和临时表执⾏ INSERT 、 UPDATE 和DELETE 操作的事务需要会写⼊以上四种类型的撤销⽇志只在普通表上执⾏ INSERT 操作的事务只需要⼀个撤消⽇志对普通表执⾏操作的事务将从指定的系统表空间或undo表空间的回滚段分配undo⽇志。对临时表执⾏操作的事务从指定的临时表空间回滚段分配undo⽇志。
7.6 InnoDB最⼤⽀持并发读写事务的数量如何计算 ✅ 解答问题 可以⽤以下公式计算InnoDB能够⽀持的并发读写事务的数量 如果每个事务执⾏ INSERT 或 UPDATE 或 DELETE 操作注意只执⾏⼀种类型的操作并发读写事务数为: 如果每个事务执⾏ INSERT 和 UPDATE 或 DELETE 操作并发读写事务数为: 如果⼀个事务在临时表上执⾏ INSERT 操作并发读写事务数为: 如果⼀个事务在临时表上执⾏ INSERT 和 UPDATE 或 DELETE 操作并发读写事务数为: 7.7 如何理解Undo链 ✅ 解答问题 Insert Undo链 和 Update Undo链采⽤了不同的组织⽅式对于新增操作Insert Undo链中的每个Undo Log都会对应⼀条新的数据⾏这个数据⾏中⽤ROLL_POINTER 信息来关联Undo Log在回滚时就可以通过它找到需要回滚的Undo Log了如图所⽰ 对于删除和更新Update Undo链中的每个Undo Log也都对应⼀个数据⾏每次更新都会通过Undo Log中的 ROLL_POINTER 进⾏关联从⽽每个数据⾏都会构成⼀个Undo Log版本链回滚的时候就可以依序撤销这个版本链在事务的MVCC中起到了⾮常重要的作⽤⽤于解决事务的隔离性相关内容在事务和锁专题中详细介绍Update Undo链如下图所⽰ 以下是⼀个关于更新操作的Undo链 7.8 撤销⽇志为什么需要落盘 分析过程 在对数据进⾏修改时都是在内存中操作的也就是在Buffer Pool中修改对应的数据⻚在修改数据⻚之前先把对应的撤销⽇志记录在内存中如果此时事务回滚直接根据内存中的撤销⽇志做回滚操作即可在修改完成提交事务后脏⻚进⾏落盘操作此时事务已提交不能回滚所以撤销⽇志也就失效了当服务器崩溃时如果事务没有提交所有的修改都在内存中还没有落盘对于修改直接丢弃如果事务已经提交则根据重做⽇志和双写缓冲区中的备份进⾏恢复通过分析看上去撤销⽇志并不需要落盘其实以上的分析场景并没有考虑到全部的场景⽐如⼤事务的运⾏、MVCC中版本链什么时候可以销毁、事务的不同隔离级别等因素 ✅ 解答问题 在运⾏⼤事务时InnoDB为了避免⼤事务提交时统⼀落盘操作带来的性能问题允许在事务进⾏的过程中就进⾏落盘操作并记录对应的UndoLog当发⽣崩溃恢复时通过回放UndoLog把未提交的事务进⾏回滚如果⼀个事务已经提交但还有其他事务需要访问版本链中对应的UndoLog那么也需要把相应的撤销⽇志保存到 hisotry list 中。不同隔离级别下没有提交的事务也可能会落盘回滚时依然要完成撤销操作
7.8.1 撤销⽇志在内存中如何记录
与数据⻚在内存中的保存⽅式相同撤销⽇志在内存中也保存在Buffer Pool中与磁盘中的UndoLog⻚结构⼀致内存中每个UndoLog⻚通过控制块管理在内存中使⽤四个链表来管理正在使⽤的UndoLog⻚和空闲UndoLog⻚根据不同的⽇志类型分为 Insert List 正在被使⽤的⽤来管理Insert类型的UndoLog ⻚Insert Cache List 空闲的或被清理后可以被后续事务重⽤的Insert类型UndoLog⻚Update List 正在被使⽤的⽤来管理Update类型的UndoLog ⻚Update Cache List 空闲的或被清理后可以被后续事务重⽤的Update类型UndoLog⻚ 7.8.2 撤销⽇志的写⼊过程是怎样的
当写事务开始时会先分配⼀个处理 ACTIVE 状态的 Rollback Segment 当第⼀次DML操作产⽣Undo Record时会轮询当前 Rollback Segment 中可⽤的 Slot 以便获取⼀个 Undo Log Segment 根据撤销⽇志的类型获取UndoLog⻚并挂载到对应的List当中在UndoLog⻚顺序写⼊⽇志当⼀个UndoLog⻚写满之后会获取新的UndoLog⻚以便继续写⼊当前事务⽣成的⽇志这⾥注意单条UndoLog不能跨⻚存储也就是说当某条⽇志在当前⻚中放不下时会整体保存下⼀⻚中由后台线程把⽇志刷⼊磁盘当事务结束之后(commit或者rollback) insert ⽇志类型对应的 Undo Log Segment 和UndoLog page 会直接回收⽽ update ⽇志类型对应的 Undo Log Segment 和UndoLog page 会等待后台的清理操作完成后确保⽇志不会有事务再访问后进⾏回收回收的UndoLog⻚被挂载到Cache List中。
7.8.3 撤销⽇志的回滚过程是怎样的
回滚操作可以是⽤⼾通过rollback主动触发也可能发⽣在崩溃恢复时不论是哪种触发条件回滚操作都是相同的基本过程就是读取该事务的Undo Log从后向前依次进⾏逆向操作从⽽恢复索引记录对于 Insert 类型的回滚操作就是 Delete 在删除的过程中会重新调整主键索引和⼆级索引对于Update和Delete类型的回滚操作主要是回退这次操作在所有主键索引和⼆级索引的影响可能包括重新插⼊被删除的⼆级索引记录、去除⾏管理信息中的Delete Mark标记、将主索引记录修改回之前的值等完成回滚的Undo Log会进⾏回收将不再使⽤的UndoLog⻚的磁盘空间还给 Undo Log Segment 这个过程是写⼊过程的逆操作。
7.8.4 撤销⽇志的清理过程是怎样的
InnoDB通过保存多份Undo Log的历史版本来实现MVCC当某个历史版本已经确认不会被任何现有的和未来的事务访问时就应该被清理掉当开启⼀个事务时都会被分配⼀个事务编号 trx_id ⽽事务进⾏读操作时会创建⼀个ReadView并记录当前所有事务中的最⼩活跃事务编号 m_low_limit_id 如果版本链中 ⽇志的trx_id m_low_limit_id 则表⽰当前读操作发⽣时⽇志对应的事务已提交其修改的新版本是可⻅的 因此不再需要通过Undo版本链构建之前的版本这个事务的Undo Log也就可以被清理了。Undo的清理⼯作是由专⻔的后台线程进⾏扫描和分发并由多个线程进⾏清理并可以通过系统变量 innodb_purge_threads 配置清理线程数系统变量 innodb_purge_batch_size可以配置每次清理的⻚数这⾥不再进⾏过多的讨论。
8 双写缓冲区 - Doublewrite Buffer 8.1 双写缓冲区的作⽤ ✅ 解答问题 双写缓冲区是磁盘上的⼀个存储区域当 InnoDB 将缓冲池中的数据⻚写⼊到磁盘上表空间数据⽂件之前先将对应的⻚写到双写缓冲区如果在数据真正落盘的过程中出现了意外退出⽐如操作系统、存储⼦系统崩溃或异常断电的情况 InnoDB 在崩溃恢复时可以从双写缓冲区中找到⼀份完好的⻚副本执⾏过程如下图所⽰ 8.1.1 双写缓冲区中的数据保存在哪⾥
在MySQL 8.0.20之前 doublewrite 缓冲区位于InnoDB系统表空间中。从MySQL 8.0.20开始 doublewrite 缓冲区默认存储区域位于数据⽬录下的 doublewrite ⽂件中。 8.2 如何配置双写缓冲区 ✅ 解答问题 是否启⽤ doublewrite 缓冲区可以通过系统变量 innodb_doublewrite[ON|OFF] 控制默认为启⽤如果真实的业务场景更关注性能⽽不是数据完整性可以考虑禁⽤doublewrite缓冲区例如在执⾏测试的环境中 doublewrite ⽂件所在⽬录通过系统变量 innodb_doublewrite_dir (MySQL 8.0.20中引⼊)指定如果不指定则在 innodb_data_home_dir ⽬录(默认为data⽬录)下创建如果指定doublewrite⽬录建议设置在最快的存储介质上以提⾼效率 命名⽅式为 #ib_page_size_file_number.dblwr 以上 #ib_16384_0.dblwr 的⽂件表⽰当前数据⻚的⼤⼩为16KB编号为0双写⽂件的数量通过系统变量 innodb_doublewrite_files 设置默认情况下为每个缓冲池实例创建两个doublewrite⽂件也就是说⽂件数量为 innodb_buffer_pool_instances* 2 此变量⽤于⾼级性能调优⼤多数场景使⽤默认设置即可
9 重做⽇志 - Redo Log 9.1 重做⽇志的作⽤
重做⽇志在保证事务的持久性和⼀致性⽅⾯起到了⾄关重要的作⽤重做⽇志⽤于在数据库崩溃后恢复已提交事务还没有来的及落盘的数据。重做⽇志以⽂件的形式保存在磁盘上在正常的操作过程中MySQL根据受影响的记录进⾏编码并写⼊重做⽇志⽂件这些数据称为Redo在重新启动时⾃动读取重做⽇志进⾏数据恢复。
9.1.1 为什么要⽤Redo Log⽽不是直接写磁盘
我们来分析⼀下⾸先明确⼀点我们对数据进⾏的DML操作都会包含在事务当中当完成修改并且提交事务之后在内存中被修改的数据⻚就要刷新到磁盘完成持久化那么如果这次DML操作对应的修改开始刷盘的话当服务器崩溃没有被刷到磁盘的数据⻚就从内存中丢失这时这个事务的修改在磁盘上就是不完整的也就是没有保证事务的⼀致性为了解决这个问题InnoDB在执⾏每个DML操作时当内存中的数据⻚修改完成之后把修改的内容以⽇志的形式保证在磁盘上然后再对数据⻚进⾏真正的落盘操作这样做就相当于对修改进⾏了⼀次备份即使当服务器崩溃也不会受到影响当服务器重启之后可以从磁盘上的⽇志⽂件中找到上次崩溃之前没有来的及落盘的数据继续执⾏落盘操作InnoDB引擎的事务采⽤了 WAL技术(Write-Ahead Logging) 基本思想是先写⽇志再写磁盘只有⽇志写⼊成功事务才算提交成功这⾥的⽇志就是Redo Log。当发⽣宕机且数据未刷到磁盘的时候可以通过Redo Log来恢复保证ACID中的持久性这也是Redo Log的作⽤。
9.1.2 Redo Log的写⼊时机
当发⽣数据修改操作时追加重做⽇志已落盘数据对应的⽇志位置被记录为⼀个检查点检查点之前的数据被置为⽆效所以重做⽇志⽂件可以循环使⽤。以⼀个更新操作为例重做⽇志的写⼊过程与时机如下图所⽰ 前⾯已经介绍过为什么要使⽤Log Buffer因为每次进⾏DML操作都会进⾏⼀次磁盘I/O这样会严重影响效率所以把⽇志统⼀写⼊内存中的Log Buffer根据刷盘策略统⼀进⾏落盘操作可以实现⼀次磁盘I/O写⼊多条⽇志从⽽提升效率。
9.2 Redo Log的格式是怎样的 分析过程 在介绍RedoLog的格式之前先来分析⼀下RedoLog中需要记录哪些内容
9.2.1 RedoLog中需要记录哪些内容
当进⾏DML操作时⾸先要修改内存中的数据⻚但是修改的数据有可能只是数据⻚中很少的⼀部分内容甚⾄有可能只修改了⼏个字节那么在RedoLog中是要记录整个数据⻚吗当然不是如果每次保存整个数据⻚的话就有太多的⽆⽤数据写⼊⽇志严重影响效率⽽且浪费空间为了节省空间提⾼效率RedoLog只记录被修改的内容⽐如当前的DML修改了哪个表空间、表空间中的哪个数据⻚数据⻚中多少偏移量处的值修改成了什么⽐如 这样就可以⽤很⼩的⽇志记录当前对数据⻚所做的修改⼤⼤节省了空间 ✅ 解答问题 RedoLog本质上只是记录了事务对数据库做了哪些修改修改操作包含多种场景⽐如对数据⾏、索引⻚的增删改对范围的修改与删除等等不同场景的 redo ⽇志定义了不同的类型但是绝⼤部分类型的 redo ⽇志都有下边这种通⽤的结构包括 Type : ⽇志类型 1BTYESpace ID : 操作所属的表空间 4BTYEPage no : 操作的数据⻚在表空间中的编号 4BTYEdata ⽇志的内容⻓度不固定 如下图所⽰: 9.2.2 data 部分的具体内容是什么
data 部分⼜可以分为数据⻚中的偏移量修改内容的⻓度和具体的修改内容如下图所⽰ 9.3 RedoLog的类型分为哪些 分析过程 查看RedoLog的类型最完整最直观的⽅式就是通过阅读源代码如下所⽰ ✅ 解答问题 RedoLog的类型根据数据操作的不同场景和对⽇志的优化⽅式有⼏⼗种之多总体可以分为 ⽤于数据⻚的⽇志类型⽐如对数据⻚的修改⽤于表空间⽂件的⽇志类型⽐如对表空间的修改⽤于表空间⽂件的⽇志类型⽐如对表空间的修改
9.4 不同⽇志类型对应了哪些操作 分析过程 ⽇志类型总体可以分为三⼤类分别是⽤于数据⻚的⽇志类型、⽤于表空间⽂件的⽇志类型和提供额外信息的⽇志类型不同的⽇志类型对应的⽇志内容也不尽相同⽽进⾏DML操作时⼤多数RedoLog属于⽤于数据⻚的⽇志类型 属于⽤于数据⻚的⽇志类型中的⼏种最常⻅数据操作所对应的⽇志类型如下 MLOG_WRITE_STRING 30 type 对应的值为30表⽰在⻚⾯的某个偏移量处写⼊⼀个字符串由于字符串的⻓度不固定需要⽤到⼀个表⽰⻓度的区域记录此时⽇志内容格式如下图所⽰ MLOG_4BYTES 4, type 对应的值为4 这种类型应⽤于对固定⻓度值的修改⽐如修改整型字段由于⻓度固定所以⽤于表⽰⻓度的区域可以省略从⽽尽可能的减少空间使⽤此时⽇志内容格式如下图所⽰ 类似的类型还有 MLOG_1BYTE 1 , MLOG_2BYTES 2 , MLOG_8BYTES 8 分别表⽰固定修改1字节、2字节、8字节的数据⽇志格式与 MLOG_4BYTES 4 相同 还有其他⼀些⽇志类型⽐如 属于⽤于表空间⽂件的⽇志类型 MLOG_FILE_CREATE 33 表⽰创建⼀个.ibd表空间⽂件MLOG_FILE_RENAME 34 表⽰重命名⼀个表空间⽂件MLOG_FILE_DELETE 35 表⽰删除⼀个表空间⽂件 属于提供额外信息的⽇志类型 MLOG_MULTI_REC_END 31 只由⼀个字节的 Type 构成⽤于标识⼀个 Mini-TransactionMTR的结尾。 Mini-Transaction可以看做是⼀组原⼦性的磁盘操作⼀个事务由⼀个或多个MTR组成 ✅ 解答问题 不同的⽇志类型对应的⽇志内容和作⽤各不相同 9.4.1 如果⼀个DML操作修改了表中的多个字段⽇志如何表⽰
上⾯的分析过程介绍了简单的DML操作对应的⽇志通常情况下⼀个DML操作会修改表中的多个字段也可能修改多条记录对于正常的增删改对应不同的⽇志类型对应⽇志所包含的主要信息如下图所⽰ 新增操作主要包含数据⻚内的偏移量主键信息新增的字段个数每个字段的内容的实际⻓度具体的内容等删除操作主要包含数据⻚内的偏移量主键信息、旧事务的Id旧roll_pointer是否删除标识更新操作主要包含数据⻚内的偏移量主键信息、旧事务的Id旧roll_pointer被更新字段的数据每个被更新字段的实际⻓度更新的具体内容 9.5 什么是Mini-Transaction 分析过程 9.5.1 DML操作会对数据⻚产⽣什么样的影响 以⼀个Insert操作为例对数据⻚的影响⼀般分为两种情况 如果写⼊记录所在的数据⻚空间充⾜⾜够存储⼀条将要写⼊的记录那么就可以直接写⼊如下图所⽰ 如果写⼊的数据⻚空间不充⾜⽆法放下这条记录由于在数据⻚中真实数据是按主键顺序排列的那么就要新建⼀个数据⻚对原来的数据进⾏调整把⼀部分数据复制到新的数据⻚中以便在⽬标数据⻚上留出⾜够的空间来保存即将写⼊的记录此时对应的⽰意图如下所⽰ 通过以上两种情况下插⼊⼀条记录的分析可以看出当数据⻚空间充⾜的情况下可以直接写⼊数据并记录⼀条对应RedoLog即可当数据⻚空间不充⾜⽆法放下这条记录的情况下会创建⼀个新数据⻚同时还有数据的复制和写⼊索引树⾮叶⼦节点上修改在实际的执⾏过程中还有对表空间中段、区中统计信息的修改等等这意味⼀个简单的Insert操作有会产⽣很多条RedoLog。
9.5.2 在记录RedoLog时服务器崩溃了导致⽇志不完整怎么办
那么这时有⼀个问题需要考虑试想⼀下如果执⾏这⼀系统操作的时候RedoLog只记录了⼀半服务器就崩溃了那么当服务器重启的时候如果按照RedoLog进⾏恢复得到的结果肯定是错误的所以在记录RedoLog的时候要保证⼀个DML所对应的⼀系列⽇志必须是完整的才可以执⾏恢复操作否则就不执⾏恢复。
9.5.3 Mini-Transaction的定义
Mini-Transaction就是针对以上的操作过程定义的概念也就是说把记录⼀个DML操作的过程称为⼀个 Mini-Transaction 简称 MTR ⼀个所谓的MTR包含⼀个DML操作产⽣的⼀组完整⽇志在进⾏崩溃恢复时这⼀组RedoLog做为⼀个不可分割的整体。这⾥所说的不可分割的组是MySQL中定义的常⻅的有 向聚簇索引对应B树的⻚⾯中插⼊⼀条记录时产⽣的RedoLog不可分割向某个⼆级索引对应B树的⻚⾯中插⼊⼀条记录时产⽣的RedoLog不可分割还有其他的⼀些对⻚⾯的访问操作时产⽣的RedoLog不可分割。 每条语句根据具体的执⾏情况可能会产⽣多个MTR。 ✅ 解答问题 Mini-Transaction是MySQL内部对底层数据⻚的⼀个原⼦操作包含⼀个DML操作产⽣的⼀组完整⽇志保证数据库异常恢复时数据⻚中数据的⼀致性。
9.5.4 如何标识⼀组RedoLog属于同⼀个MTR
在执⾏DML操作的过程中每⼀个对数据⻚的修改都会记录⼀条RedoLog这些⽇志会被顺序记录下来并在这组⽇志的最后加⼀条特殊的⽇志标识作为⼀个MRT的结尾这条特殊的⽇志结构⾮常简单只有⼀个 TYPE 字段类型为 MLOG_MULTI_REC_END 31 也就是⽇志分类中的提供额外信息的⽇志类型⼀个MTR对应的⽇志组如下图所⽰ 9.5.5 如果⼀个MTR中只有⼀条⽇志是否可以优化
当然可以如果⼀个MTR只有⼀条⽇志直接在这条⽇志后加⼀个类型为MLOG_MULTI_REC_END 31 的标识可以做为MTR的结尾但这样做有点浪费空间InnoDB为了尽可能的节省空间在MTR只有⼀条⽇志的情况下做了⼀个优化。通过上⾯的介绍了解了⽇志类型虽然很多但也只有⼏⼗种⽽⽤来表⽰⽇志类型的 TYPE 字段⻓度为 1BTYE ,⽽这 1BTYE 中只⽤7个⽐特位代表整数127就完全可以表⽰所有的⽇志类型与是省出来⼀个⽐特位就可以⽤来表⽰当前MTR包含⼀条还是⼀组RedoLog也就是说如果 TYPE 字段的第⼀个⽐特位为 1 表⽰MTR只包含⼀条RedoLog为 0 表⽰MTR包含⼀组RedoLog如下图所⽰ 9.5.6 事务与Mini-Transaction是什么关系
Mini-Transaction是包含的是⼀个DML操作对应的⼀组RedoLog⽽⼀个事务中可能会包含多个DML操作所以⼀个事务中包含⼀个或多个SQL语句⼀个SQL语句包含⼀个或多个MRT⼀个MTR包含⼀条或多条RedoLog他们之间的关系如下图所⽰ 9.6 RedoLog的是如何写⼊缓冲区的 前置知识 这个问题可以理解为RedoLog的写⼊过程要了解写⼊过程必须先介绍RedoLog在内存和⽂件中是如何进⾏描述和组织的我们提出以下⼏个问题
9.6.1 ⽤来组织RedoLog的数据结构是什么
⽤来组织RedoLog的数据结构是Redo⻚⻚的⼤⼩是 512B 也可以称为⼀个 Redo LogBlock 这个⼤⼩刚好对应磁盘上⼀个扇区当⽇志写⼊磁盘时可以保证连续性 Redo Log Block 的⽰意图如下所⽰ 在⼀个 Redo Log Block 中包含⽤来存储管理信息的块头 Log Block Header (占12Byte)和块尾 Log Block Trailer (占4Byte)其他的空间是真正⽤来存储⽇志的区域 Log Block Body (占496B)
9.6.2 Log Block Header和Log Block Trailer都记录了哪些信息
Log Block Header 和 Log Block Trailer 包含的信息如下图所⽰ Log Block Header LOG_BLOCK_HDR_NO Block的唯⼀标识是⼀个⼤于0的值取值范围1~0x40000000UL⽽0x40000000UL对应的整数是1073741824即1GB也就是说InnoDB最多能够⽣成1GB个⽇志块每个⽇志块为512B所以InnoDB允许维护⽇志的最⼤容量为 512GB 在后⾯介绍配置⽇志相关的选项时关于⽇志容量的⼤⼩就是以此为依据LOG_BLOCK_HDR_DATA_LEN 表⽰Block中已经使⽤了多少字节由于块头占⽤了12B的空间所以初始值为12当 Log Block Body 被全部写满时那么这个值就是512LOG_BLOCK_FIRST_REC_GROUP 如果⼀个MTR会⽣产多条redo⽇志记录这些⽇志记录被称之为⼀个redo⽇志记录组 LOG_BLOCK_FIRST_REC_GROUP 代表该Block中第⼀个MTR中第⼀条⽇志的偏移量。 Log Block Trailer LOG_BLOCK_CHECKSUM 表⽰Block的校验和⽤于正确性校验。
9.6.3 Redo Log Block在Log Buffer中是如何组织的
在内存中RedoLog存储在⽇志缓冲区(Log Buffer)中⽇志缓冲区是服务器启动时向操作系统申请的⼀⽚连续的内存区域并被划分成若⼲个连续的 Redo Log Block ⽤来存储即将要写⼊磁盘⽇志⽂件的数据如下图所⽰ ⽇志缓冲区⼤⼩可以通过系统变量 innodb_log_buffer_size 指定默认⼤⼩为 16MB 取值范围1048576(1MB) ~ 4294967295(4GB) 分析过程 向⽇志缓冲区中写⼊⽇志是⼀个顺序写⼊的过程也就是从缓冲区的第⼀个 Redo Log Block 的 Log Block Body 开始依次向后写⼀个block的空间空间⽤完之后再写下⼀个block那么有⼀个⾸先要解决的问题当有⼀记⽇志需要写⼊缓冲区时应该往哪个block中的哪个位置写呢
9.6.4 从⽇志缓冲区写RedoLog时从内存中的哪个地址开始写
InnoDB 的提供了⼀个名为 buf_free 的全局变量该变量表⽰后续写⼊⽇志在 Log Buffer中的起始位置如图所⽰ 9.6.5 不同的事务在并发执⾏时如何记录RedoLog
通过前⾯的介绍了解到InnoDB以MTR为单位记录RedoLog⼀个事务中包含多个MTR⼀个MTR包含多条RedoLog这些RedoLog是⼀个不可分割的⽇志组⼀个事务在执⾏过程中并不是每⽣成⼀条RedoLog就写⼊到Log Buffer中⽽是把⽣成的RedoLog先缓存在内存的⼀个区域中当⼀个MTR执⾏完成后把这组⽇志⼀起复制到Log Buffer假设有两个事务T1, T2并发执⾏每个事务中都包含2个MRT即事务T1包含mtr_t1_1和mtr_t1_2T2包含mtr_t2_1和mtr_t2_2如下图所⽰在并发环境下不同事务中的MTR是交替执⾏的当MTR执⾏完成之后对应⽣成的RedoLog会被写⼊ Log Buffer
所以在Log Buffer中⽇志的写⼊形式如下图所⽰
需要说明⼀点不同的MTR产⽣的⽇志组占⽤的存储空间可能不⼀样有的MTR产⽣的⽇志很少有的MTR产⽣的⽇志量⾮常多。 ✅ 解答问题 RedoLog在内存中⽤Redo⻚进⾏组织称为 Redo Log Block 每个 Redo Log Block ⼤⼩固定为512B对应磁盘上⼀个扇区⽇志被顺序安排在 Log Block Body 中在Log Buffer中多个 Redo Log Block 顺序排列 Redo Log Block 的个数由Log Buffer的⼤⼩决定当执⾏事务时不同的语句对应不同的数据库操作⼀条SQL语句可能包含多个MTR⼀个MTR包含多条RedoLogMTR中的多条⽇志称为⼀个⽇志组写⼊Log Buffer的⽇志是以MTR对应的⽇志组为⼀个单位这组⽇志不可分割。
9.7 Redo Log的刷盘时机 分析过程 当⼀个MTR执⾏完成后RedoLog会被写⼊Log Buffer⽽Log Buffer⼤⼩是有限的并且这些记录⽇志的⽬的是为了服务器崩溃后的数据恢复在内存中保存也不安全所以在把它们刷到磁盘上进⾏保存 ✅ 解答问题 InnoDB在以下情况会把RedoLog刷到磁盘 Log Buffer 空间不⾜时Log Buffer⼤⼩是有限的可以通过系统变量innodb_log_buffer_size 设置如果当前Log Buffer中的RedoLog占⽤了Log Buffer总容量⼀半左右会触发刷盘事务提交时当事务提交时事务中对应的MTR已经完全记录在了Log Buffer中在数据真正落盘之前需要把对应的RedoLog刷新到磁盘后台线程定时刷盘后台的 Master Thread 线程⼤约每秒都会把Log Buffer中的RedoLog刷新到磁盘正常关闭服务器时在服务关闭之前会把会把Log Buffer中的RedoLog刷新到磁盘做检查点( checkpoint )操作时
9.7.1 刷盘策略可以进⾏配置吗
可以⽇志缓冲区的内容定期刷新到磁盘可以通过系统变量 Innodb_flush_log_at_timeoutN 设置N默认为1单位为秒通过设置系统变量 innodb_flush_log_at_trx_commit 设置写⼊和刷盘策略默认值为1 0 ⽇志每秒写⼊系统缓冲区并刷新到磁盘未写⼊系统缓冲区的事务⽇志可能会在MYSQL崩溃时丢失1 ⽇志在每次事务提交时写⼊系统缓冲区并刷新到磁盘2 ⽇志在每次事务提交后写⼊系统缓冲区并每秒⼀次刷新到磁盘未刷新到磁盘的⽇志可能在系统崩溃时丢失。 如果启⽤⼆进制⽇志且设置 sync_binlog 1 时则必须设置innodb_flush_log_at_trx_commit 1
9.7.2 不同的刷盘策略有什么影响
⾸先看⼀下Log Buffer、操作系统缓存和磁盘中⽇志⽂件的关系如图所⽰ 这⾥主要讨论系统变量 innodb_flush_log_at_trx_commit 对应的⼏种情况 值为0时表⽰⽇志每秒写⼊操作系统缓存并刷新到磁盘如果MySQL崩溃那么在⼀秒内没有写⼊操作系统缓存的Redo Log将会丢失值为2时⽇志在每次事务提交后写⼊系统缓冲区并每秒⼀次刷新到磁盘此时已提交的事务Redo Log全部都写⼊了操作系统缓存MySQL⽆论是否崩溃Redo Log都会以指定的时间刷新到磁盘但是如果服务器崩溃或断电将会导致操作系统缓存中的Redo Log丢失值为 1 时⽇志在每次事务提交时写⼊系统缓冲区并刷新到磁盘此时Redo Log从Log Buffer中写⼊操作系统缓存并⽴即刷新到磁盘从⽽尽可能的保证⽇志的完整性推荐使⽤。
9.8 Redo Log对应磁盘上的⽂件是什么 分析过程 重做⽇志⽂件位于数据⽬录下的 #innodb_redo ⽬录中重做⽇志⽂件分为普通类型和备⽤类型普通类型是正在使⽤的⽇志⽂件备⽤是准备使⽤的⽇志⽂件InnoDB 共维护 32 个重做⽇志⽂件每个⽂件的⼤⼩等于 1⁄32 * innodb_redo_log_capacity重做⽇志⽂件使⽤ #ib_redoN 命名约定其中 N 是重做⽇志⽂件编号备⽤的重做⽇志⽂件使⽤ _tmp 为后缀。如下⽰例显⽰有21个活动(普通)重做⽇志⽂件和11个备⽤重做⽇志⽂件 每个普通的重做⽇志⽂件都与⼀个特定的 LSN 取值范围相关联⽤于崩溃恢时快速定位到要执⾏重做的⽇志可以使⽤下⾯的查询显⽰活动重做⽇志⽂件的 START_LSN 和 END_LSN 值 ✅ 解答问题 重做⽇志⽂件位于数据⽬录下的 #innodb_redo ⽬录中在MySQL8.0中InnoDB 共维护 32 个重做⽇志⽂件每个⽂件的⼤⼩等于 1⁄32 * innodb_redo_log_capacity重做⽇志⽂件分为普通类型和备⽤类型并且使⽤ #ib_redoN 命名约定其中 N 是重做⽇志⽂件编号备⽤的重做⽇志⽂件使⽤ _tmp 为后缀重做⽇志的总容量可以通过系统变量 innodb_redo_log_capacity 设置8.0.34版本开始最⼤为512GB
9.8.1 这么多⽇志⽂件⽇志写到哪个⽂件中
通过查看 #innodb_redo ⽬录可以看到系统⽣成了32个RedoLog⽂件当RedoLog从内存刷到磁盘时先从第⼀个⽇志⽂件开始写第⼀个写满之后顺序写到第⼆个以此类推如果最后⼀个也写满了就会重新从第⼀个⽂件开始写也就是说重做⽇志⽂件可以循环使⽤如图所⽰ 这⾥可能会出现⼀个问题如果循环写⼊的话那么后写⼊的⽇志会不会把之前写⼊的内容覆盖了当然有这个可能为了解决这个问题InnoDB提出checkpoint的概念关于checkpoint后⾯会详细介绍。
9.8.2 什么是LSN LSN是 Log Sequence Number 的简写称为⽇志序号 MySQL在运⾏期间只要执⾏DML操作就会修改数据⻚意味着会不断的⽣成RedoLogInnoDB为了记录⽣成的⽇志总量(字节数)设计了⼀个只增不减的全局变量这个全局变量就是LSN起始值 16*512 8192 最⼤值 2^64 - 1 当⼀个MTR所包含的⼀组RedoLog被记录在 Redo Log Block 中时实际是保存在 Log Block Body 区域但是在统计LSN增量时如果MTR跨 Block 保存时是按照实际写⼊的⽇志⼤⼩加上 Log Block Header 所占的12Byte)和块尾 Log Block Trailer 所占4Byte ⽰例 系统启动后初始化Log Bufferbuf_free指向第⼀个block偏移量为12Byte的位置也就是block Header之后此时LSN也会增加12即8192 12 8204假设MTR_1中包含的⼀组RedoLog⼤⼩为200Byte那么LSN就会在原来的基础上加200即8204 200 8404假设MTR_2中包含的⼀组RedoLog⼤⼩为1000Byte这⾥当前的Block_1已经放不下这个MTR于是⽇志顺序保存在后⾯的Block中占满第⼆个Block后直到使⽤了第三个Block的⼀部分空间⽇志保存完成 这时LSN不但要记录MTR_2中⽇志的总⼤1000Byte还要记录Block_1Block_2的Log BlockTrailer和Block_2Block_3的Log Block Header总⼤⼩为1000 12 * 2 4 * 2 1032此时LSN的值为8404 1032 9436如下图所⽰ 9.9 Redo Log⽇志⽂件的格式 分析过程 9.9.1 Log Buffer中的Redo Log Block与磁盘中的Redo Log Block有哪些不同 在内存中Log Buffer是⼀⽚连续的内存空间被划分成了若⼲个 512 字节⼤⼩的 Redo Log Block ⽤来保存Redo Log将Log Buffer中的Redo Log刷新到磁盘本质就是把 Redo Log Block 的写⼊⽇志⽂件中所以Redo Log对应的⽇志⽂件其实也是由若⼲个 512 字节⼤⼩的block 组成。MySQL会根据配置⽣成⼀组撤销⽇志⽂件每个⽂件的格式和⼤⼩都⼀样由两部分组成 管理区前 2048 个字节也就是前4个block存储⼀些⽇志⽂件的管理信息数据区从第2048字节往后是⽤来存储Log Buffer对应的 Redo Log Block 也就是说真实的⽇志是从每个⽇志⽂件的第2048个字节开始写⼊如图所⽰ 所以Log Buffer中的Redo Log Block与磁盘中的Redo Log Block在结构上是相同的只不过在磁盘上多了⽤于⽂件管理的⽂件头信息 ✅ 解答问题 磁盘中RedoLog的格式与内存中的格式相同在内存中Log Buffer是⼀⽚连续的内存空间被划分成了若⼲个 512 字节⼤⼩的 Redo Log Block ⽤来保存Redo Log将Log Buffer中的Redo Log刷新到磁盘本质就是把 Redo Log Block 的写⼊⽇志⽂件中所以Redo Log对应的⽇志⽂件其实也是由若⼲个 512 字节⼤⼩的 block 组成只不过在磁盘上多了⽤于⽂件管理的⽂件头信息。
9.9.2 重做⽇志⽂件管理区包含哪些信息
关于 Redo Log Block 的结构与内存结构相同前 2048字节 分为4个Block分别为 LOG_CHECKPOINT_1 第⼀个⽇志⽂件中⽇志头的第⼀个检查点信息LOG_ENCRYPTION ⽇志⽂件头信息中的加密信息LOG_CHECKPOINT_2 第⼀个⽇志⽂件中⽇志头的第⼆个检查点信息LOG_FILE_HDR_SIZE ⽇志⽂件头信息 9.9.3 管理区中具体管理了什么信息
管理区各字段中的信息随着MySQL版本迭代变化⾮常⼤这⾥主要介绍⼀些关键信息LOG_CHECKPOINT_1 、 LOG_CHECKPOINT_2 主要是记录CHECKPOINT操作时对应的LSNLSN会交替写⼊到 LOG_CHECKPOINT_1 和 LOG_CHECKPOINT_2 中具体写⼊规则后⾯介绍LOG_ENCRYPTION LOG_FILE_HDR_SIZE 中的加密信息LOG_FILE_HDR_SIZE 主要记录⽇志⽂件的⼀些信息主要包括 LOG_HEADER_FORMAT 占4字节⽇志的格式标识和MySQL版本相关有重⼤更新的版本才设置相应的值在MySQL5.7.9之前⼀直都是0LOG_HEADER_START_LSN 占8字节⽇志⽂件中第⼀个LSN编号LOG_HEADER_CREATOR 占32字节记录⽇志的创建者正常⽣成的⽇志⼀般为MEBMySQL的版本号如果是运⾏ mysqlbackup 程序在备份过程中⽣成的⽇志则记录MySQL的版本号
9.10 什么是CHECKPOINT - 检查点 分析过程 RedoLog从内存刷到磁盘上的⽇志⽂件使⽤循环写⼊的⽅式也就是从第⼀个⽇志⽂件顺序写到最后⼀个⽇志⽂件当最后⼀个⽇志⽂件写满时⼜重新写第⼀个⽇志⽂件那么就可能出现⽇志被覆盖的情况那么哪些⽇志可以被覆盖哪些不能被覆盖呢
9.10.1 哪些RedoLog可以被覆盖
⾸先回顾⼀下RedoLog的作⽤RedoLog是⽤作崩溃后恢复没有完成落盘的事务也就是说当Buffer Pool中的脏⻚写⼊RedoLog但数据⻚还没有落盘时发⽣的崩溃当服务器重启之后可以根据RedoLog进⾏恢复这也是RedoLog的应⽤时机所以这种状态下的RedoLog不能被覆盖如下图所⽰ 如果缓冲池中的脏⻚在记录RedoLog之后也完成了真正的落盘操作那么相应的RedoLog就没有⽤了所以这部分RedoLog就可以被覆盖如下图所⽰ 经过分析可以看出判断⽇志⽂件中的RedoLog是否可以覆盖的依据是它对应的数据⻚是否已经刷新到磁盘。
9.10.2 如何记录可以覆盖的⽇志⽂件位置
前⾯介绍过InnoDB使⽤LSN是来记录RedoLog总字节数在这个基础上InnoDB采⽤⼀个全局变量checkpoint_lsn 来记录当前系统中可以被覆盖⽇志总量是多少也就是说checkpoint_lsn 记录已落盘脏⻚对应的⽇志结束时LSN的值此时LSN⼩于checkpoint_lsn 的RedoLog就可以被覆盖如图所⽰ 当脏⻚刷新到磁盘之后重新计算 checkpoint_lsn 的操作称为⼀次 CHECKPOINT 操作也可以说是重置⼀次检查点系统会⽤⼀个 checkpoint_no 变量记录发⽣ CHECKPOINT 操作的次数每做⼀ CHECKPOINT 操作 checkpoint_no 就会加1由于RedoLog⽂件的⼤⼩是固定的在系统启动时已经分配好了对应的 Redo Log Block 所以很容易就可以根据 checkpoint_lsn 计算写⼊位置在⽇志⽂件中的偏移量关于检查点相关的 checkpoint_no 、 checkpoint_lsn 以及写⼊偏移量的信息会被记录在第⼀个⽇志⽂件的管理区同时InnoDB规定当checkpoint_no的值是偶数时写到checkpoint1 中是奇数时写到 checkpoint2 中。 ✅ 解答问题 CHECKPOINT 也称为检查点由于RedoLog⽂件是可以循环使⽤的当最后⼀个⽂件写满时⼜会从第⼀个⽂件开始写⼊这必将导致⽼的⽇志被覆盖 CHECKPOINT 是标记已被刷新到磁盘的脏⻚刷对应的RedoLog可以被覆盖的⼀种操作当⽇志的LSN⼩于已落盘脏⻚对应的LSN都可以被覆盖。
9.10.3 如果没有⼩于 checkpoint_lsn 的⽇志时如何处理
如果⽇志⽂件中没有⼩于 checkpoint_lsn 的⽇志时表明⽇志⽂件已经使⽤完了这时原来的⽇志不能被覆盖InnoDB会先优先刷新脏⻚到磁盘再做 CHECKPOINT 操作之后再继续进⾏⽇志记录。
9.11 重做⽇志还有哪些主要的配置项 分析过程 重做⽇志在磁盘上所占的空间可以通过系统变量 innodb_redo_log_capacity 控制变量值以字节为单位最⼤值 549755813888 表⽰ 512GB 可以在选项⽂件或在运⾏时使⽤ SET GLOBAL 语句进⾏设置如下所⽰
将RedoLog的最⼤容量设置为8GB
SET GLOBAL innodb_redo_log_capacity 8589934592;重做⽇志的⽬录可以通过系统变量 innodb_log_group_home_dir 进⾏设置如果没有指定则⽇志⽂件位于数据⽬录的 #innodb_redo ⽬录中如果定义了innodb_log_group_home_dir 变量则⽇志⽂件存放在该⽬录下的 #innodb_redo ⽬录中 ✅ 解答问题 根据实际应⽤场景通过配置对应的系统变量来指定 Redo Log 在磁盘上所占的空间的⼤⼩、所在⽬录等属性。
9.12 如何查看重做⽇志的状态
通过状态变量 innodb_redo_log_capacity_resized 显⽰当前重做⽇志容量限制: 可以通过查询 performance_schema.innodb_redo_log_files 表来查看活动重做⽇志⽂件的信息 通过使⽤ SHOW ENGINE InnoDB STATUS 访问 InnoDB 标准监视器输出中 LOG 部分查看有关Redo Log的信息 9.13 如何根据RedoLog进⾏崩溃恢复 分析过程 在MySQL正常运⾏时RedoLog不仅发挥不了它的作⽤⽽且还会对服务器的性能造成影响但是服务器⼀旦崩溃在重新启动时就可以根据RedoLog中的记录把数据⻚恢复到崩溃前的状态
9.13.1 如何确定哪些⽇志需要恢复
前⾯我们介绍过每⼀次 CHECKPOINT 操作都会重新计算 checkpoint_lsn checkpoint_lsn 之前的⽇志表⽰已经被刷到磁盘数据⻚所⽣成的RedoLog既然已被刷到磁盘也就没有必要进⾏恢复所以需要恢复的是 checkpoint_lsn 之后的⽇志
9.13.2 如何获取最新的 checkpoint_lsn 和恢复的起点
RedoLog⽂件组中的第⼀个⽂件的管理信息中有两个block checkpoint1 和 checkpoint2 其中都存储了 checkpoint_lsn 和 checkpoint_no 信息每次做 CHECKPOINT 操作时会在这两个block中交替写⼊ CHECKPOINT 信息只要需要把这两个block中保存的checkpoint_no 值⽐较⼀下哪个值⼤就表⽰哪个block存储的就是最近的⼀次checkpoint信息。这样我们就能拿到最近发⽣的 checkpoint 对应的 checkpoint_lsn 值以及它在RedoLog⽂件组中的偏移量 checkpoint_offset 。
9.13.3 如何确认恢复的终点
我们⽤之前已经掌握的内容分析⼀下这个问题⾸先RedoLog是顺序写⼊的当⼀个block写满了之后再写下⼀个⽽每⼀个block的 log block header 中都有⼀个名为LOG_BLOCK_HDR_DATA_LEN 的属性该属性记录了当前block使⽤了多少字节对于写满的block来说该值⼀定是 512 所以找到第⼀个 LOG_BLOCK_HDR_DATA_LEN 的值不为512就可以确定恢复扫描的最后⼀个block这个block中的最后⼀条⽇志就是恢复的终点。
9.13.4 如何进⾏恢复
确定了需要扫描哪些⽇志进⾏崩溃恢复之后接下来就是怎么进⾏恢复了假设现在的⽇志⽂件中有RedoLog如图所⽰ 第⼀条⽇志在 checkpoint_lsn 之前表⽰已经落盘不⽤恢复 checkpoint_lsn 之后的⽇志可以通过顺序扫描的⽅式根据⽇志记录的内容依次恢复对应的数据⻚ InnoDB在顺序读取⽇志进⾏恢复的过程中采⽤了⼀些优化措施⾸先根据⽇志的 Space Id 和Page No 计算出散列值以这个散列值为 KEY 把 Space Id 和 Page No 相同的⽇志放到哈希表的同⼀个槽⾥如果有多个 Space Id 和 Page No 相同的⽇志那么按照⽇志⽣成的先后顺序使⽤链表连接起来如下图所⽰ 组织好⽇志后通过遍历哈希表就可以⼀次把⼀个数据⻚中的修改全部恢复好减少了读取数据⻚时的随机I/O次数
9.13.5 如何确定哪些⽇志在崩溃前已经落盘 checkpoint_lsn 之后的⽇志有可能就根本没有落盘也有可能已经落盘但没有来的及做CHECKPOINT 在恢复时如何区分呢 在⻚结构章节介绍过磁盘上的每个⻚都包含⼀个 File Header 信息其中⼜包含已被刷到磁盘的LSN FIL_PAGE_FILE_FLUSH_LSN 信息在恢复时就可以通过当前⽇志对应的LSN与FIL_PAGE_FILE_FLUSH_LSN 进⾏⽐较如果⽇志的LSN⼩于已刷新到磁盘的LSN那就证明⽇志对应的数据在崩溃之前已经落盘直接跳过即可 ✅ 解答问题 恢复的过程主要分为以下⼏步 通过 checkpoint_lsn 和第⼀个没有写满的⽇志⻚确定需要恢复⽇志的起始和结束位置 遍历⽇志并把Space Id 和 Page No相同的⽇志组织在⼀起以便⼀次性恢复完相应数据⻚的所有内容 ⽇志的LSN⼩于磁盘数据⻚⽂件记录的已刷新LSN时表⽰这些数据在崩溃之前已落盘跳过即可。
⼩结
相关文章
-
wordpress 界面英文版官网seo怎么做
wordpress 界面英文版官网seo怎么做
- 站长
- 2026年02月18日
-
wordpress 建站教程 下载南阳千牛网站建设
wordpress 建站教程 下载南阳千牛网站建设
- 站长
- 2026年02月18日
-
wordpress 建站教程 .pdf网络维护是做什么
wordpress 建站教程 .pdf网络维护是做什么
- 站长
- 2026年02月18日
-
wordpress 框架选择青岛seo代理计费
wordpress 框架选择青岛seo代理计费
- 站长
- 2026年02月18日
-
wordpress 轮播图代码网站seo推广优化
wordpress 轮播图代码网站seo推广优化
- 站长
- 2026年02月18日
-
wordpress 逻辑代码seo整站如何优化
wordpress 逻辑代码seo整站如何优化
- 站长
- 2026年02月18日
