2.mysql 中一条更新语句的执行流程是怎样的呢?

前面我们系统了解了一个查询语句的执行流程,并介绍了执行过程中涉及的处理模块。

相信你还记得,一条查询语句的执行过程一般是经过连接器、分析器、优化器、执行器等功能模块,最后到达存储引擎。

那么,一条更新语句的执行流程又是怎样的呢?

从一个表的一条更新语句说起,下面是这个表的创建语句,这个表有一个主键 ID 和一个整型字段 c:

mysql> create table T(ID int primary key, c int);
-- 如果要将 ID=2 这一行的值加 1,SQL 语句就会这么写:
mysql> update T set c=c+1 where ID=2;

更新语句是如何实现的呢?

前面我有跟你介绍过 SQL 语句基本的执行链路,这里我再把那张图拿过来,你也可以先简单看看这个图回顾下。首先,可以确定的说,查询语句的那一套流程,更新语句也是同样会走一遍。

img

MySQL 的逻辑架构图

你执行语句前要先连接数据库,这是连接器的工作。

前面我们说过,在一个表上有更新的时候,跟这个表有关的查询缓存会失效,所以这条语句就会把表 T 上所有缓存结果都清空。这也就是我们一般不建议使用查询缓存的原因。

接下来,分析器会通过词法和语法解析知道这是一条更新语句。优化器决定要使用 ID 这个索引。然后,执行器负责具体执行,找到这一行,然后更新。

与查询流程不一样的是,更新流程还涉及两个重要的日志模块,它们正是我们今天要讨论的主角:redo log(重做日志)和 binlog(归档日志)。

如果接触 MySQL,那这两个词肯定是绕不过的,我后面的内容里也会不断地和你强调。不过话说回来,redo log 和 binlog 在设计上有很多有意思的地方,这些设计思路也可以用到你自己的程序里。

Redo Log 日志

Redo Log:指事务中修改的任何数据,将最新的数据备份存储的位置(Redo Log),被称为重做日志。(Redo:顾名思义就是重做。以恢复操作为目的,在数据库发生意外时重现操作。)

Innodb存储引擎特有日志

redo log是一种WAL技术应用,英文全称为write-aheading-log

具体来说,当有一条记录需要更新的时候,InnoDB 引擎就会先把记录写到 redo log (先写磁盘,只是写日志是顺序写盘,速度很快)里面,并更新内存,这个时候更新就算完成了。

同时,InnoDB 引擎会在适当的时候,将这个操作记录更新到磁盘binlog里面,而这个更新往往是在系统比较空闲的时候做。

为何有会采用这种技术呢?

因为执行一条SQL更新语句就去写磁盘,需要先在磁盘上查找对应的行,再进行更新,整个过程无论是IO操作,还是查找操作消耗都很大;

因此mysql存储引擎Innodb采用将数据先写入到redo log,然后更新内存,这样就算完成一条更新语句,然后在适当的时候再将数据更新到磁盘中。 

同时该技术能够解决crash-safe问题,当系统突然崩溃时,可以通过redo log恢复崩溃前的状态。

Redo Log特性

Redo Log 的生成和释放:

随着事务操作的执行,就会生成Redo Log,在事务提交时会将产生,Redo Log写入Log Buffer,并不是随着事务的提交就立刻写入磁盘文件。

等事务操作的脏页写入到磁盘之后,Redo Log 的使命也就完成了,Redo Log占用的空间就可以重用(被覆盖写入)。

Redo Log 的写入方式:

InnoDB 的 redo log 是固定大小的,比如可以配置为:一组 4 个文件,每个文件的大小是 1GB,那么这块“粉板”总共就可以记录 4GB 的操作。

从头开始写,写到末尾就又回到开头循环写,如下面这个图所示。

两个关键的位置节点: write pos(写入位置) , chech point(擦除位置)

write pos 是当前记录的位置,一边写一边后移,写到第 3 号文件末尾后就回到 0 号文件开头。

checkpoint 是当前要擦除的位置,也是往后推移并且循环的,擦除记录前要把记录更新到数据文件binlog。

write pos 和 checkpoint 之间的是“粉板”上还空着的部分,可以用来记录新的操作。

如果 write pos 追上 checkpoint,代表内存快写满了,脏页很多,需要强制刷盘,这时候不能再执行新的更新,得停下来先擦掉一些记录,把 checkpoint 推进一下。

有了 redo log,InnoDB 就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力称为 crash-safe。(崩溃-安全)

Redo Log相关配置参数

每个InnoDB存储引擎至少有1个重做日志文件组(group),每个文件组至少有2个重做日志文件,默认为ib_logfifile0和ib_logfifile1。可以通过下面一组参数控制Redo Log存储:

show variables like '%innodb_log%';Redo Buffer 持久化到 Redo Log 的策略,可通过 Innodb_flush_log_at_trx_commit 设置:0:每秒提交 Redo buffffer ->OS cache -> flflush cache to disk,可能丢失一秒内的事务数据。由后台Master线程每隔 1秒执行一次操作。1(默认值):每次事务提交执行 Redo Buffffer -> OS cache -> flflush cache to disk,最安全,性能最差的方式。2:每次事务提交执行 Redo Buffffer -> OS cache,然后由后台Master线程再每隔1秒执行OS cache -> flflush cache to disk 的操作。一般建议选择取值2,因为 MySQL 挂了数据没有损失,整个服务器挂了才会损失1秒的事务提交数据。

Binlog 归档日志

Redo Log 是属于InnoDB引擎所特有的日志,而MySQL Server也有自己的日志,即 Binarylog(二进制日志),简称Binlog。

Binlog是记录所有数据库表结构变更以及表数据修改的二进制日志,不会记录SELECT和SHOW这类操作。

我想你肯定会问,为什么会有两份日志呢?

因为最开始 MySQL 里并没有 InnoDB 引擎。MySQL 自带的引擎是 MyISAM,但是 MyISAM 没有 crash-safe 的能力,binlog 日志只能用于归档。而 InnoDB 是另一个公司以插件形式引入 MySQL 的,既然只依靠 binlog 是没有 crash-safe 能力的,所以 InnoDB 使用另外一套日志系统——也就是 redo log 来实现 crash-safe 能力。

这两种日志有以下三点不同。

  1. redo log 是 InnoDB 引擎特有的;binlog 是 MySQL 的 Server 层实现的,所有引擎都可以使用。
  2. redo log 是物理日志,记录的是“在某个数据页上做了什么修改”;binlog 是逻辑日志,记录的是这个语句的原始逻辑,比如“给 ID=2 这一行的 c 字段加 1 ”。
  3. redo log 是循环写的,空间固定会用完;binlog 是可以追加写入的。“追加写”是指 binlog 文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。

Binlog日志是以事件形式记录

文件记录模式有STATEMENT、ROW和MIXED三种,具体含义如下。

1. ROW(row-based replication, RBR):日志中会记录每一行数据被修改的情况,然后在slave端对相同的数据进行修改。

        优点:能清楚记录每一个行数据的修改细节,能完全实现主从数据同步和数据的恢复。

        缺点:批量操作,会产生大量的日志,尤其是alter table会让日志暴涨。

2. STATMENT(statement-based replication, SBR):每一条被修改数据的SQL都会记录到master的Binlog中,

slave在复制的时候SQL进程会解析成和原来master端执行过的相同的SQL再次执行。简称SQL语句复制。

优点:日志量小,减少磁盘IO,提升存储和恢复速度

缺点:在某些情况下会导致主从数据不一致,比如last_insert_id()、now()等函数。

3. MIXED(mixed-based replication, MBR):

        以上两种模式的混合使用,一般会使用STATEMENT模式保存binlog,对于STATEMENT模式无法复制的操作使用ROW模式保存binlog,MySQL会根据执行的SQL语句选择写入模式。

update 语句时的内部流程

        了解了两个日志,那么执行器和 InnoDB 引擎在执行这个简单的 update 语句时,具体是如何使用这两份日志的呢? update 语句时的内部流程。

1.执行器先找引擎取 ID=2 这一行。ID 是主键,引擎直接用树搜索找到这一行。如果 ID=2 这一行所在的数据页(page页 16k大小)本来就在内存中,就直接返回给执行器;否则,需要先从磁盘读入内存,然后再返回。

2.执行器拿到引擎给的行数据,把这个值加上 1,比如原来是 N,现在就是 N+1,得到新的一行数据,再调用引擎接口写入这行新数据。

3.引擎将这行新数据更新到内存中,同时将这个更新操作记录到 redo log 里面,此时 redo log 处于 prepare 状态。然后告知执行器执行完成了,随时可以提交事务。

4.执行器生成这个操作的 binlog,并把 binlog 写入磁盘。执行器调用引擎的提交事务接口,引擎把刚刚写入的 redo log 改成提交(commit)状态,更新完成。

大致流程如下:

最后三步看上去有点“绕”,将 redo log 的写入拆成了两个步骤:prepare 和 commit,这就是"两阶段提交"。

两阶段提交

为什么必须有“两阶段提交”呢?这是为了让redo log 和 binlog 两份日志之间的逻辑一致

用前面的 update 语句来做例子。假设当前 ID=2 的行,字段 c 的值是 0,再假设执行 update 语句过程中在写完第一个日志后,第二个日志还没有写完期间发生了 crash,会出现什么情况呢?

mysql> update T set c=c+1 where ID=2;

由于 redo log 和 binlog 是两个独立的逻辑,如果不用两阶段提交,要么就是先写完 redo log 再写 binlog,或者采用反过来的顺序。我们看看这两种方式会有什么问题。

1. 先写 redo log 后写 binlog。

假设在 redo log 写完,binlog 还没有写完的时候,MySQL 进程异常重启。

由于我们前面说过的,redo log 写完之后,系统即使崩溃,仍然能够把数据恢复回来,所以恢复后这一行 c 的值是 1。但是由于 binlog 没写完就 crash 了,这时候 binlog 里面就没有记录这个语句。

因此,之后备份日志的时候,存起来的 binlog 里面就没有这条语句。然后你会发现,

如果需要用这个 binlog 来恢复临时库的话,由于这个语句的 binlog 丢失, 这个临时库就会少了这一次更新,恢复出来的这一行 c 的值就是 0,与原库的值不同。

2.先写 binlog 后写 redo log。

如果在 binlog 写完之后 crash,由于 redo log 还没写,崩溃恢复以后这个事务无效,所以这一行 c 的值是 0。

但是 binlog 里面已经记录了“把 c 从 0 改成 1”这个日志。所以,在之后用 binlog 来恢复的时候就多了一个事务出来,恢复出来的这一行 c 的值就是 1,与原库的值不同。

应用设置:

1.redo log 用于保证 crash-safe 能力。innodb_flush_log_at_trx_commit 这个参数设置成 1 的时候,表示每次事务的 redo log 都直接持久化到磁盘。这个参数我建议你设置成 1,这样可以保证 MySQL 异常重启之后数据不丢失。

2.sync_binlog 这个参数设置成 1 的时候,表示每次事务的 binlog 都持久化到磁盘。这个参数我也建议你设置成 1,这样可以保证 MySQL 异常重启之后 binlog 不丢失。

小结

今天,我介绍了 MySQL 里面最重要的两个日志,即物理日志 redo log 和逻辑日志 binlog。

redo log 用于保证 crash-safe 能力。innodb_flush_log_at_trx_commit 这个参数设置成 1 的时候,表示每次事务的 redo log 都直接持久化到磁盘。

这个参数我建议你设置成 1,这样可以保证 MySQL 异常重启之后数据不丢失。

sync_binlog 这个参数设置成 1 的时候,表示每次事务的 binlog 都持久化到磁盘。

这个参数我也建议你设置成 1,这样可以保证 MySQL 异常重启之后 binlog 不丢失。

我还跟你介绍了与 MySQL 日志系统密切相关的“两阶段提交”。两阶段提交是跨系统维持数据逻辑一致性时常用的一个方案,即使你不做数据库内核开发,日常开发中也有可能会用到。

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

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

相关文章

JavaScript根据数据生成柱形图

分析需求 // 定义一个数组来存储四个季度的数据 dataArray = []// 循环4次,获取用户输入的数据并存储到数组中 for i from 0 to 3// 获取用户输入的数据inputData = 获取用户输入的第(i + 1)季度的数据// 将数据存入数组dataArray[i] = inputData// 遍历数组,根据数据生成柱…

实验13 使用预训练resnet18实现CIFAR-10分类

1.数据预处理 首先利用函数transforms.Compose定义了一个预处理函数transform,里面定义了两种操作,一个是将图像转换为Tensor,一个是对图像进行标准化。然后利用函数torchvision.datasets.CIFAR10下载数据集,这个函数有四个常见的…

【AI系统】代数简化

代数简化 代数简化(Algebraic Reduced)是一种从数学上来指导我们优化计算图的方法。其目的是利用交换率、结合律等规律调整图中算子的执行顺序,或者删除不必要的算子,以提高图整体的计算效率。 代数化简可以通过子图替换的方式完…

多人聊天室项目 BIO模型实现

BIO模型聊天室项目大体设计 BIO编程模型 Acceptor是服务器端负责监听具体端口的Socket每有一个客户端Client连接到服务器端,Acceptor就创建一个新的线程Handler来处理客户端发送的消息每一个客户端都有一个唯一的Handler来对应处理其事务为保证线程安全&#xff0c…

腾讯云平台 - Stable Diffusion WebUI 下载模型

1)进入控制台,点击算力连接 》 JupyterLab 2)进入模型目录(双击) 3)上传模型 例如:我要上传大模型

夜神模拟器+Charles+postern+Mgisk+TrustMeAlready实现抓包

[实测有用]夜神模拟器CharlesposternMgiskTrustMeAlready实现抓包 PS:此贴仅做为技术交流,禁止非法用途。 1.初始化条件 A.安装MUMU模拟器安卓12版本 B.按图示选择,设置好代理端口8889 C.查看本机IP地址 D.导出证书,安装配置,暂时保存…

【closerAI ComfyUI】物体转移术之图案转移,Flux三重控制万物一致性生图,实现LOGO和图案的精准迁移

更多AI前沿科技资讯,请关注我们:closerAI-一个深入探索前沿人工智能与AIGC领域的资讯平台 closerAIGCcloserAI,一个深入探索前沿人工智能与AIGC领域的资讯平台,我们旨在让AIGC渗入我们的工作与生活中,让我们一起探索AIGC的无限可能性! 【closerAI ComfyUI】物体转移术之图…

新质驱动·科东软件受邀出席2024智能网联+低空经济暨第二届湾区汽车T9+N闭门会议

为推进广东省加快发展新质生产力,贯彻落实“百县千镇万村高质量发展工程”,推动韶关市新丰县智能网联新能源汽车、低空经济与数字技术的创新与发展,充分发挥湾区汽车产业链头部企业的带动作用。韶关市指导、珠三角湾区智能网联新能源汽车产业…

vue+mars3d给影像底图叠加炫酷效果

话不多说,直接上效果图: 在这里墙体其实是有一个不太明显的流动效果 实现方式:这里我使用了PolylineEntityWallPrimitive,开始我用的是polygonEntity但是发现实现效果并不好,所有直接改用了线 map.vue文件&#xff1…

【模电】常见电路参数计算

1.恒流源输出电阻 2.射极电压跟随器输出电阻 3.差分放大电路 3.1差模特性 3.1.1差模输入电阻Rid 3.1.2差模输出电阻Ro 3.1.3差模电压增益Avd 3.2共模特性 3.2.1共模输入电阻Ric 3.2.2共模电压增益Avc 4.组合放大电路 4.1单级放大器 4.1.1微变等效电路 4.1.1.1共射级 4.1.…

Linux-虚拟环境

文章目录 一. 虚拟机二. 虚拟化软件三. VMware WorkStation四. 安装CentOS操作系统五. 在VMware中导入CentOS虚拟机六. 远程连接Linux系统1. Finalshell安装2. 虚拟机网络配置3. 连接到Linux系统 七. 虚拟机快照 一. 虚拟机 借助虚拟化技术,我们可以在系统中&#…

Kafka如何保证消息可靠?

大家好,我是锋哥。今天分享关于【Kafka如何保证消息可靠?】面试题。希望对大家有帮助; Kafka如何保证消息可靠? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Kafka通过多种机制来确保消息的可靠性,主要包…

ONVIF协议网络摄像机客户端使用gsoap获取RTSP流地址GStreamer拉流播放

什么是ONVIF协议 ONVIF(开放式网络视频接口论坛)是一个全球性的开放式行业论坛,旨在促进开发和使用基于物理IP的安全产品接口的全球开放标准。 ONVIF规范的目标是建立一个网络视频框架协议,使不同厂商生产的网络视频产品完全互通。…

javaweb_Day05

1.请求响应 1.1 概述 1.2 请求 1.2.1 请求参数 1.2.2 响应 2.分层解耦 2.1 三层架构 (1)代码分层 2.2 分层解耦 2.3 IOC&DI入门 (1)控制反转IOC (2)依赖注入DI (3)汇总 …

Stable Diffusion 3详解

🌺系列文章推荐🌺 扩散模型系列文章正在持续的更新,更新节奏如下,先更新SD模型讲解,再更新相关的微调方法文章,敬请期待!!!(本文及其之前的文章均已更新&…

[VUE]框架网页开发02-如何打包Vue.js框架网页并在服务器中通过Tomcat启动

在现代Web开发中,Vue.js已经成为前端开发的热门选择之一。然而,将Vue.js项目打包并部署到生产环境可能会让一些开发者感到困惑。本文将详细介绍如何将Vue.js项目打包,并通过Tomcat服务器启动运行。 1. 准备工作 确保你的项目能够正常运行,项…

网络分层模型( OSI、TCP/IP、五层协议)

1、网络分层模型 计算机网络是一个极其复杂的系统。想象一下最简单的情况:两台连接在网络上的计算机需要相互传输文件。不仅需要确保存在一条传输数据的通路,还需要完成以下几项工作: 发起通信的计算机必须激活数据通路,这包括发…

采药 刷题笔记 (动态规划)0/1背包

P1048 [NOIP2005 普及组] 采药 - 洛谷 | 计算机科学教育新生态 动态规划 0/1背包 的本质在于继承 一行一行更新 上一行是考虑前i个物品的最优情况 当前行是考虑第i1个物品的情况 当前行的最优解 来自上一行和前i个物品的最优解进行比较 如果当前装了当前物品&#xff…

汽车操作系统详解

目录 1. 车控汽车操作系统 2. 车载汽车操作系统 3. OEM定制操作系统 刚开始工作的时候,接触的是汽车控制相关的开发工作,天真地以为汽车操作系统就是指实时操作系统,例如FreeRTOS、OSEK OS、AUTOSAR OS等等;然而,随…

Shire 1.1 发布:更强大的交互支持,升级 AI 智能体与 IDE 的整合体验

在经过多个项目上的试用后,我们进入了持续的修修补补,以及功能的增强阶段。终于,我们发布了 Shire 1.1 版本,这个版本带来了更强大的交互支持, 多功能升级 AI 与 IDE 的整合体验。 交互:丰富与大量 IDE 插件…