MySQL中的 redolog

什么是redo log

        如果我们只在内存的 Bufer Pool中修改了页面,假设在事务提交后突然发生了某个故障导致内存中的数据都失效了,那么这个已经提交的事务在数据库中所做的更改也就跟着丢失了,这是我们所不能忍受的。那么,如何保证这个持久性呢?一个很简单的做法就是在事务提交完成之前,把该事务修改的所有页面都刷新到磁盘。不过这个简单粗暴的做法存在下面这些问题。

        刷新一个完整的数据页太浪费了。有时我们仅仅修改了某个页面中的一个字节,但是由于InnoDB 是以页为单位来进行磁盘I/O的,也就是说在该事务提交时不得不将一个完整的页面从内存中刷新到磁盘。我们又知道,一个页面的默认大小是16KB,因为修改了一个字节就要刷新 16KB的数据到磁盘上,显然太浪费了。随机 I/O 刷新起来比较慢。

        一个事务可能包含很多语句,即使是一条语句也可能修改许多页面,“倒霉催”的是该事务修改的这些页面可能并不相邻。这就意味着在将某个事务修改的 Bufer Pool中的页面刷新到磁盘时,需要进行很多的随机 I/O。随机 I/O 比顺序 I/O 要慢,尤其是对于传统的机械硬盘。

         所以,其实没有必在每次提交事务时就把该事务在内存中修改过的页面全部刷新到磁盘,只需要记录有哪些就该就可以。

        这样在事务提交时,就会把上述内容刷新到磁盘中。即使之后系统崩溃了,重启之后只要照上述内容所记录的步骤重新更新一下数据页,那么该事务对数库中所体的修改可以恢复出来,这样也就意味着满足持久性的要求。

        我们把这类日志叫做redo log日志。

        redo 日志占用的空间非常小,在存储表空间ID、页号、偏移量以及需要更新的值时需要的存储空间很小。
redo 日志是顺序写入磁盘的,在执行事务的过程中,每执行一条语句,就可能产生若干条 redo 日志,这些日志是按照产生的顺序写入磁盘的,也就是使用顺序 I/O。

redolog日志格式

redo 日志中各个部分的详细解释如下:

type :这条 redo 日志的类型。
page number:页号。
space ID:表空间 ID。
data :这条 redo 日志的具体内容。

简单的redolog日志

        如果没有为某个表显式地定义主键,并且表中也没有定义不允许存储 NULL值的 UNIQUE键,那么InnoDB 会自动为表添加一个名为row_id的隐藏列作为主键。为这个row id 隐藏列进行赋值的方式如下。服务器会在内存中维护一个全局变量,每当向某个包含row_id隐藏列的表中插入一条记录时,就会把这个全局变量的值当作新记录的row_id列的值,并且把这个全局变量自增1。
每当这个全局变量的值为256的倍数时,就会将该变量的值刷新到系统表空间页号为7的页面中一个名为MaxRowID的属性中(前文介绍表空间结构时详细说过该属性。之所以不是每次自增该全局变量时就将该值刷新到磁盘,是为了避免频刷盘)
当系统启动时,会将这个MaxRowD属性加载到内存中,并将该值加上 256之后赋
值给前面提到的全局变量(因为在系统上次关机时,该全局变量的值可能大于磁盘页面中 Max Row ID 属性的值)。
这个 Max RowID 属性占用的存储空间是8字节。当某个事务向某个包含 row_id隐藏列的表插入一条记录,并且为该记录分配的row_id值为256的倍数时,就会向系统表空间页号头7的页面的相应偏移量处写入8字节的值。但是我们要知道,这个写入操作实际上是在Bufe Pool中完成的,我们需要把这次对这个页面的修改以redolog日志的形式记录下来。这样在事务提交之后,即使系统崩溃了,也可以将该页面恢复成崩溃前的状态。在这种对页画的修改是极其简单的情况下,redo 日志中只需要记录一下在某个页面的某个偏移量处修改了几个字节的值、具体修改后的内容是啥就好了。这种极其简单的redo 日志称为物理日志,并且根据在页面中写入数据的多少划分了几种不同的redo 日志类型。

复杂一些的 redo 日志类型

        有时,在执行一条语句时会修改非常多的页面,包括系统数据页面和用户数据页面(用户数据指的就是聚簇索引和二级索引对应的 B+树)。以一条INSERT 语句为例,它除了向 B+树的页面中插入数据外,也可能更新系统数据MaxRowID的值。不过对于用户来说,平时更关心的是语句对B+树所做的更新。

        表中包含多少个索引,一条INSERT 语句就可能更新多少棵 B+树。针对某一棵B+树来说,既可能更新叶子节点页面,也可能更新内节点页面,还可能创建新的页面(在该记录插入的叶子节点的剩余空间比较少,不足以存放该记录时,会进行页面分裂,在内节点页面中添加目录项记录)。

        在语句执行过程中,INSERT语句对所有页面的修改都得保存到redo log日志中去。这句话说的比较轻巧,做起来可就比较麻烦了。比如,在将记录插入到聚簇索引中时,如果定位到的叶子节点的剩余空间足够存储该记录,那么只更新该叶子节点页面,并只记录一条 MLOGWRITE STRING类型的redo日志,表明在页面的某个偏移量处增加了哪些数据不就好了么?那就天真了。别忘了,一个数据页中除了存储实际的记录之外,还有FileHeader、PageHeader、Page Directory等部分(在第5章有详细讲解)。所以每往叶子节点代表的数据页中插入一条记录,还有其他很多地方会跟着更新,比如:

可能更新 Page Directory 中的槽信息;
可能更新 Page Header 中的各种页面统计信息,比如 PAGE_N_DIR_SLOTS 表示的槽数量可能会更改,PAGEHEAPTOP代表的还未使用的空间最小地址可能会更改,PAGENHEAP代表的本页面中的记录数量可能会更改……

        说了这么多,就是想表达:在把一条记录插入到一个页面时,需要更改的地方非常多。这时如果使用前面介绍的简单的物理redo 日志来记录这些修改,可以有两种解决万案。

        方案1:在每个修改的地方都记录一条redo日志。按照这种方式来记录redo 日志的缺点是显而易见的,因为被修改的地方实在太多了,可能redo 日志占用的空间都要比整个页面占用的空间多。
方案 2:将整个页面第一个被修改的字节到最后一个被修改的字节之间所有的数据当成一条物理 redo 日志中的具体数据。
正是因为在使用上面这两个方案来记录某个页面中做了哪些修改时,比较浪费空间,设计ImnoDB 的大叔本着勤俭节约的初心,提出了一些新的redo 日志类型。
MLOG REC INSERT(type 字段对应的十进制数字为9):表示在插入一条使用非紧凑行格式(REDUNDANT)的记录时,redo日志的类型,MLOG COMP RECINSERT(type 字段对应的十进制数字为38):表示在插入一条使用紧凑行格式(COMPACT、DYNAMIC、COMPRESSED)的记录时,redo 日志的类型。MLOG COMP PAGE CREATE(type 字段对应的十进制数字为 58):表示在创建一个存储紧凑行格式记录的页面时,redo日志的类型。
MLOG_COMP REC DELETE(type 字段对应的十进制数字为 42):表示在删除一条使用紧凑行格式记录时,redo日志的类型。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/916562.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/916562.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构之 【排序】(非递归实现快速排序)

目录 1.引入 2.非递归实现快排的思想 3.非递归实现快排图解 4.完整代码 1.引入 递归不可避免的话题就是防止栈溢出 所以程序员需要具备递归改非递归的能力 ,一般来说,抓住递归中变化的量是关键 void QuickSort(int* a, int left, int right){if (left…

CLAP文本-音频基础模型: LEARNING AUDIO CONCEPTS FROM NATURAL LANGUAGE SUPERVISION

一、TL;DR 现在的做法有什么问题?主流范式是 “一个类别标签对应多个录音”,需要提前标注预测预先定义的类别,只能做闭集理解,失去灵活性 我们怎么做?通过两个编码器和对比学习机制建立语言与音频的关联&a…

Flink2.0学习笔记:Stream API 常用转换算子

EC0720/FLINKTASK-TEST-STREAM/demo at master stevensu1/EC0720 先看测试效果:控制台 测试效果:监控服务端 主要的转换算子包括: 转换算子 filter:过滤包含“Flink”的输入 转换算子 map: 将每行数据前添加“Processed: ”并转为大写 转…

一、Python环境、Jupyter与Pycharm

安装Python由于RAG项目中所需要的Python版本必须高于3.8,经过筛选,最终选择了3.10.11这个版本py --version Python 3.10.11安装过程略过,但对于几个基础的命令作个笔记记录where python找到python启动器的位置D:\>where python C:\Users\x…

Flink CEP 动态模板与规则动态修改实践完全手册

1. Flink CEP:从静态规则到动态江湖 Flink 的复杂事件处理(CEP)库就像一个武功高强的侠客,能从数据流中精准捕获特定模式,堪称流处理界的“降龙十八掌”。但问题来了:传统 CEP 规则通常是写死在代码里的,就像刻在石碑上的武功秘籍,改起来费劲不说,还得重启应用,简直…

vue3.2 + echarts5.6 + ant-design-vue 3.x 实现自定义 echarts 图例

文章目录概要技术细节效果概要 需求需要实现图例移入显示描述说明 故实现自定义图例 技术细节 <template><div class"custom-legend"><divv-for"item in legends":key"item.name"class"legend-item":class"{ i…

【2025年7月25日】TrollStore巨魔商店恢复在线安装

就在今日7月25日&#xff0c;TrollStore的在线安装功能再次变得可用&#xff0c;这对于许多iPhone用户来说无疑是个喜讯。在经历了近三个月的中断后&#xff0c;巨魔商店的企业证书意外的到来了&#xff0c;使得用户能够重新采用在线安装的方式&#xff01; 在线安装地址在文…

【05】C#入门到精通——C# 面向对象、类、静态变量static、类与类之间的调用

文章目录1 引入例子2 创建类2.1 类的访问属性2.2 英雄 特点类2.3 英雄信息打印3 静态变量static4 类 调用 类4.1 非静态 成员函数4.2 静态 成员函数1 引入例子 比如游戏中 描述英雄的角色&#xff0c; 我们可以像下面这样&#xff0c;给每一个英雄特点及拥有技能分别定义变量…

单片机的硬件结构

单片机的硬件结构 一、课程导入 在上一节课《认识单片机》中&#xff0c;我们知道单片机就像一个超级迷你的工厂&#xff0c;有着类似工厂的各个组成部分。而这个 “迷你工厂” 能正常运转&#xff0c;离不开其内部严谨的硬件结构。就像一座大厦&#xff0c;只有基础结构稳固且…

multiprocessing模块使用方法(二)

spawn_main是Python multiprocessing模块的核心内部函数&#xff0c;用于实现spawn启动方法的子进程初始化。以下结合代码Demo详细说明其使用方法和推荐场景。一、spawn_main的功能与定位核心作用&#xff1a; 在spawn模式下启动子进程&#xff0c;负责进程间通信管道的建立和资…

编程与数学 03-002 计算机网络 07_路由算法

编程与数学 03-002 计算机网络 07_路由算法一、静态路由算法&#xff08;一&#xff09;手工配置路由表的方法&#xff08;二&#xff09;静态路由的优缺点二、动态路由算法原理&#xff08;一&#xff09;距离矢量算法&#xff08;如贝尔曼 - 福特算法&#xff09;&#xff08…

使用Python,OpenCV计算跑图的图像彩色度

使用Python&#xff0c;OpenCV计算跑图的图像彩色度 这篇博客将介绍如何计算跑图里最鲜艳的top25图片和最灰暗的top25图片并显示色彩彩色度值展示。 效果图 以下分别是最鲜艳top25和最灰暗top25对比效果图&#xff1a; 最鲜艳top25效果图&#xff1a; 最灰暗top25效果图…

LeetCode 60:排列序列

LeetCode 60&#xff1a;排列序列问题定义与核心挑战 给定整数 n 和 k&#xff0c;返回集合 {1,2,...,n} 的第 k 个字典序排列。直接生成所有排列再遍历到第 k 个的方法&#xff08;时间复杂度 O(n!)&#xff09;会因 n≥10 时阶乘爆炸而超时&#xff0c;因此需要 数学推导 贪…

亚远景-传统功能安全VS AI安全:ISO 8800填补的标准空白与实施难点

一、为什么需要ISO 8800&#xff1a;传统安全标准的“盲区”传统功能安全&#xff08;ISO 26262&#xff09;• 假设&#xff1a;系统行为可被完整规格化&#xff0c;失效模式可枚举&#xff0c;风险可用概率-危害矩阵量化。• 盲区&#xff1a;对“设计意图正确&#xff0c;但…

菜鸟教程 R语言基础运算 注释 和数据类型

菜鸟教程 R语言基础运算 注释 和数据类型 1.注释 注释主要用于一段代码的解析&#xff0c;可以让阅读者更易理解&#xff0c;编程语言的注释会被编译器忽略掉&#xff0c;且不会影响代码的执行。 一般编程语言的注释分为单行注释与多行注释&#xff0c;但是 R 语言只支持单行注…

华为云ELB(弹性负载均衡)持续报异常

华为云ELB&#xff08;弹性负载均衡&#xff09;持续报异常&#xff0c;需结合实例类型&#xff08;共享型/独享型&#xff09;和异常代码进行针对性排查。以下是分步排查建议&#xff1a;一、根据实例类型排查网络配置共享型实例 安全组规则&#xff1a;检查后端服务器安全组是…

《R for Data Science (2e)》免费中文翻译 (第2章) --- Workflow: basics

写在前面 本系列推文为《R for Data Science (2)》的中文翻译版本。所有内容都通过开源免费的方式上传至Github&#xff0c;欢迎大家参与贡献&#xff0c;详细信息见&#xff1a; Books-zh-cn 项目介绍&#xff1a; Books-zh-cn&#xff1a;开源免费的中文书籍社区 r4ds-zh-cn …

开源深度学习新宠:Burn框架助您无忧高效建模

在日新月异的人工智能世界里&#xff0c;各类深度学习框架如雨后春笋般涌现&#xff0c;而Burn&#xff0c;作为新一代的深度学习框架&#xff0c;以其不妥协的灵活性、高效性和可移植性崭露头角。本文将深入探讨Burn的核心功能、应用场景及具体使用方法&#xff0c;帮助您更好…

基于深度学习的图像分割:使用DeepLabv3实现高效分割

前言 图像分割是计算机视觉领域中的一个重要任务&#xff0c;其目标是将图像中的每个像素分配到不同的类别中。近年来&#xff0c;深度学习技术&#xff0c;尤其是卷积神经网络&#xff08;CNN&#xff09;&#xff0c;在图像分割任务中取得了显著的进展。DeepLabv3是一种高效的…

如何高效合并音视频文件(时间短消耗资源少)(二)

英语字幕 1 00:00:06,480 --> 00:00:08,400 Good morning. We have a banger for you2 00:00:08,400 --> 00:00:09,840 today. We&amp;#39;re going to launch chatbt3 00:00:09,840 --> 00:00:11,519 agent. But before jumping into that, I&amp;#39;d4 00…