一条 update 语句的执行过程

news2024/11/7 21:06:12

1.一条 update 语句的执行流程

一条更新语句,其实是增,删,查的综合体,查询语句需要经过的流程,更新语句全部需要执行一次,因为更新之前必须要先拿到(查询)需要更新的数据。

Buffer Pool

InnnoDB 的数据都是放在磁盘上的,而磁盘的速度和 CPU 的速度之间有难以逾越的鸿沟,为了提升效率,就引入了缓冲池技术,在 InnoDB 中称之为 Buffer Pool。

从磁盘中读取数据的时候,会先将从磁盘中读取到的页放在缓冲池 Buffer Pool 中,这样下次读相同的页的时候,就可以直接从 Buffer Pool 中获取。

更新数据的时候首先会看数据在不在缓冲池中,在的话就直接修改缓冲池中的数据。注意,前提是我们不需要对这条数据进行唯一性检查(因为如果要进行唯一性检查就必须加载磁盘中的数据来判断是否唯一了)。

如果只修改了 Buffer Pool 中的数据而不修改磁盘中数据,这时候就会造成内存和磁盘中数据不一致,这种也叫做脏页。InnoDB 里面有专门的后台线程把 Buffer Pool 的数据写入到磁盘, 每隔一段时间就一次性地把多个修改写入磁盘,这个动作就叫做刷脏。

那么现在有一个问题,假如我们更新都需要把数据写入数据磁盘,然后磁盘也要找到对应的那条记录,然后再更新,整个过程 IO 成本、查找成本都很高。为了解决这个问题,InnoDB 就有了 redo log,并且采用了 Write-Ahead Logging(WAL) 方案来实现。

2.redo log

redo log,即重做日志,是 InnoDB 引擎所特有,主要用于崩溃修复(crash-safe)。

举个例子,读书的时候我们听课会做笔记,而做笔记的目的就是为了忘了之后可以复习, redo log 的作用也是一样,一旦 MySQL 因为异常宕机,就可以利用 redo log 进行恢复。

Write-Ahead Logging(WAL)

Write-Ahead Logging,即日志先行,也就是说我们执行一个操作的时候会先将操作写入日志,然后再写入数据磁盘,那么有人就会问了,写入数据表是磁盘操作,写入 redo log 也是磁盘操作,同样都是写入磁盘,为什么不直接写入数据,而要先写入日志呢?这不是多此一举吗?

设想一下,假如我们所需要的数据是随机分散在不同页的不同扇区中,那么我们去找数据的时候就是随机 IO 操作,而redo log 是循环写入的,也就是顺序 IO。

一句话:刷盘是随机 I/O,而记录日志是顺序 I/O,顺序 I/O 效率更高。因此先把修改写入日 志,可以延迟刷盘时机,进而提升系统吞吐量。

redo log 如何刷盘

nnoDB 中的 redo log 是固定大小的,也就是说 redo log 并不是随着文件写入慢慢变大,而是一开始就分配好了空间,空间一旦写满了,前面的空间就会被覆盖掉,刷盘的操作是通过 Checkpoint 实现的。如下图:
在这里插入图片描述
check point 是当前要覆盖的位置。write pos 是当前写入日志的位置。写日志的时候是循环写的,覆盖旧记录前要把记录更新到数据文件。如果 write pos 和 check point 重叠,说明 redo log 已经写满,这时候需要强制将 redo log 中的数据刷到磁盘中。

上图中粉红色的其实是一个文件,绿色的也是一个文件,这里其实画成一个圆形会更形象,因为数据是循环写的,默认配置下 redo log 有两个文件,每个文件大小是 48MB,可以通过以下两个变量控制:

SHOW VARIABLES LIKE 'innodb_log_files_in_group'; -- 设置redo log文件个数
SHOW VARIABLES LIKE 'innodb_log_file_size';-- 设置每个文件的大小

在这里插入图片描述

3.bin log

上面讲的 redo log 是 InnoDB 引擎特有的日志,而 Server 层也有自己的日志,称为 binlog(归档日志),也叫做二进制日志。

可能有人会问,为什么会有两份日志呢? 因为最开始 MySQL 里并没有 InnoDB 引擎。MySQL 自带的引擎是 MyISAM,但是 MyISAM 是不支持事务的,也没有崩溃恢复(crash-safe)的能力,binlog 日志只能用于归档。那么既然 InnoDB 需要支持事务,那么就必须要有崩溃恢复(crash-safe)能力,所以就使用另外一套自己的日志系统,也就是 redo log。

bin log 和 redo log 的区别

  1. redo log 是 InnoDB 引擎特有的,而 binlog 是 MySQL 的 Server 层实现的,所有引擎都可以使用。

  2. redo log 是物理日志,记录的是“在某个数据页上做了什么修改”,而 binlog 是逻辑日志,记录的是这个语句的原始逻辑,比如“给 id=2 这一行的 c 字段加 1 ”。

  3. redo log 是循环写的,空间固定会用完,而 binlog 是可以追加写入的。“追加写”是指 binlog文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。

4.update 语句的执行流程

前面铺垫了这么多,主要是想让大家先理解 redo log 和 bin log 这两个概念,因为更新操作离不开这两个日志文件,接下来我们正式回到正题,一条 update 语句到底是如何执行的,可以通过下图表示:
在这里插入图片描述
上图可以大概概括为以下几步:

  1. 先根据更新语句的条件,查询出对应的记录,如果有缓存,也会用到缓存。

  2. Server 层调用 InnoDB 引擎的 API 接口,InnoDB 引擎将这条数据写到内存,同时写入 redo log,并将redo log 状态设置为 prepare。

  3. 通知 Server 层,可以正式提交数据了。

  4. Server 层收到通知后立刻写入 bin log,然后调用 InnoDB 对应接口发出 commit 请求。

  5. InnoDB 收到 commit 请求后将数据设置为 commit 状态,完成此时事务。

上面的步骤中,我们注意到,redo log 会经过两次提交,这就是两阶段提交法。

5.两阶段提交

两阶段提交是分布式事务的设计思想,就是首先会有请求方发出请求到各个服务器,然后等其他各个服务器都准备好之后再通知请求方可以提交了,请求方收到请求后再发出指令,通知所有服务器一起提交。

而我们这里 redo log 是属于存储引擎层的日志,bin log 是属于 Server 层日志,属于两个独立的日志文件,采用两阶段提交就是为了使两个日志文件逻辑上保持一致。

假如不采用两阶段提交法

假如有一条数据 id=1,name=张1,我们现在要把这条数据的 name 更新为 张11:

  • 先写 redo log 后写 bin log:

假设在 redo log 写完,binlog 还没有写完的时候,MySQL 发生了宕机。重启后因为 redo log 写完了,所以会自动进行数据恢复,也就是 张11。但是由于 binlog 没写完就宕机(了,这时候 bin log 里面就没有记录这个语句。然后某一天假如我们把数据丢失了,需要用 bin log 进行数据恢复就会发现少了这一次更新。

  • 先写 bin log 后写 redo log:

假如在 binlog 写完,redo log 还没有写完的时候,MySQL 发生了宕机。重启后因为 redo log 没写完,所以无法进行自动恢复,那么数据就还是 name=张1 了,然后某一天假如我们把数据丢失了,需要用 bin log 进行恢复又会发现恢复出来的数据 name=张11 了。

通过以上的两个假设我们就会发现,假如不采用两阶段提交法就会出现数据不一致的情况,尤其是在有主从库的时候,因为主从复制是基于 binlog 实现的,如果 redo log 和 bin log 不一致,就会导致主从库数据不一致。

宕机后的数据恢复规则

采用两阶段提交后,假如数据库发生宕机,那么会遵循以下两条规则进行数据恢复:

  1. 如果 redo log 里面的事务是完整的,也就是已经有了 commit 标识,则直接提交。

  2. 如果 redo log 里面的事务只有完整的 prepare,则判断对应的事务 bin log是否存在并完整:如果是,则提交事务;否则,回滚事务。

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

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

相关文章

低代码平台组件间通信方案复盘

背景介绍3年前我开发了一款零代码搭建平台 H5-Dooring, 主要目的是想用更低的成本, 更快的效率, 上线 web 页面(其实是不想写重复的代码了,写麻了). 好在陆陆续续折腾了3年, 目前已经可以满足基本的页面设计和搭建能力, 并能快速上线页面.之前也在社区分享了很多低代码和零代码…

高、低成本MEMS惯导系统姿态、位置、速度更新算法的对比

高、低成本MEMS惯导系统姿态、位置、速度更新算法的对比一、高成本MEMS惯导系统姿态、位置、速度更新算法1、速度更新2、位置更新3、姿态更新4、程序仿真及实验结果4.1 主函数4.2 子函数4.3 实验结果一、低成本MEMS惯导系统姿态、位置、速度更新算法1、速度更新2、位置更新3、姿…

乾元浩在创业板IPO终止:主要生产禽用疫苗产品,中农大是股东

2023年1月4日,深圳证券交易所披露的信息显示,乾元浩生物股份有限公司(下称“乾元浩”)提交了撤回上市申请文件的申请,保荐人中信证券也撤回对该公司的保荐。因此,深交所终止了乾元浩首次公开发行股票并在创…

程序员述职报告

程序员述职报告笔者能力有限,仅供参考。做研发的小伙伴,不太擅长于写PPT,对于更高一级别的领导,可能只有年终述职的时候才能全面的了解你的工作。所以需要我们在PPT中表达自我价值,突出角色职责。让领导更清楚的认识你…

访问数据库超时问题排障

1 排障过程 系统从圣诞节那天晚上开始,每天晚上固定十点多到十一点多这个时段,大概瘫痪1h左右,过这时段系统自动恢复。系统瘫痪时的现象就是,网页和App都打不开,请求超时。系统架构: 整个系统托管在公有云…

图解数据结构:盘点链表与栈和队列的那些血缘(单双链表模拟实现栈和队列)

写在前面 Hello,各位盆友们,我是黄小黄。关于前一段时间为什么拖更这件事,这里给大家说一句抱歉。笔者前段时间忙于ddl和一些比赛相关的事件,当然还有些隐藏任务,所以博文更新就放缓了。  这里还需要做一下对以后博文…

计算机原理一_计算机的组成、进程与线程

目录儿一、计算机组成二、进程与线程2.1 线程的切换2.2 CPU的并发控制2.2.1 关中断2.2.2 缓存一致性协议2.2.2.1 缓存Cache2.2.2.2 缓存行Cache Line2.2.2.3 缓存一致性拓展:超线程2.2.3 内存屏障2.2.3.1 CPU的乱序执行拓展1:java 的 this 溢出问题拓展2…

Linux(一):Linux基本结构

一、Linux系统划分 linux系统分为用户区、内核区 1.1分区目标 保护数据和硬件安全,对系统进行分区也就是进程分区,当处于用户态,只能访问用户区,用户无法修改内核,保证硬件安全,操作系统不易损坏&#…

【Qt】QMainWindow应用程序窗口类简单介绍

QMainWindow介绍 QMainWindow是一个为用户提供主窗口程序的类,是许多应用程序的基础,包含的组件有: 菜单栏QMenuBar,一个主窗口最多只能有一个菜单栏;包含一个下拉菜单项的列表,这些菜单项由QAction动作类…

【git版本控制】| git版本控制操作命令(全)

文章目录一、简介二、工作模式1 集中式(CVS、SVN)2 分布式Git三、Git1 工作模式2 git工作流程3 工作区和版本库4 注意事项5 基本操作5.1 创建本地版本库5.2 初始化本地版本库5.3 .git目录的作用5.4 创建用户5.5 其他操作6 git分支7 常见警告8 免密登录9 …

interface接口--GO面向对象编程思想

一、interface接口 interface 是GO语言的基础特性之一。可以理解为一种类型的规范或者约定。它跟java,C# 不太一样,不需要显示说明实现了某个接口,它没有继承或子类或“implements”关键字,只是通过约定的形式,隐式的…

【C语言进阶】自定义类型:结构体,枚举,联合体

目录 1、结构体的声明 1.1 结构体基础知识 1.2 结构体的声明 1.3 特殊的声明 1.4 结构体的自引用 1.5 结构体变量的定义和初始化 1.6 结构体内存对齐 ​编辑1.7 修改默认对齐数 1.8 结构体传参 2. 位段 2.1 什么是位段 2.2 位段的内存分配 2.3 位段的跨平台问…

【owt-server】代码结构及新增一个agent

owt server 官方 5.0 仓库:代码结构 manage console manage api portal sip portal 与agent 并列 agent又有很多种类。 启动脚本 启动一个新的agent 比如streaming-agent streaming-agent )cd ${OWT_HOME}/s

分布式id

分布式id一 什么是分布式系统唯一ID二 分布式系统唯一ID的特点三 分布式系统唯一ID的实现方案3.1 基于UUID3.2 基于数据库自增id3.3 基于数据库集群模式3.4 基于Redis模式3.5 基于雪花算法(Snowflake)模式3.6 百度(uid-generator)…

Python爬虫数据到sqlite实例

参考链接:https://blog.csdn.net/qq_45775027/article/details/115319253最近需要使用到爬虫数据库,原文中作者有些没补齐,略作修改之后跑通了。主要修改:1.调整了数据获取的正则表达式;2. 改了一下数据库的table名和定义名字&…

基于Java+SpringBoot+vue+element实现前后端分离牙科诊所管理系统详细设计

基于JavaSpringBootvueelement实现前后端分离牙科诊所管理系统详细设计 博主介绍:5年java开发经验,专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 欢迎点赞 收藏 ⭐留言 文末获取源码联系方式 文章目…

【Linux】虚拟地址空间 --- 虚拟地址、空间布局、内存描述符、写时拷贝、页表…

该吃吃,该喝喝,遇事儿别往心上隔😎 文章目录一、虚拟地址空间1.虚拟地址的引出(看不到物理地址,只能看看虚拟地址喽)2.虚拟地址空间布局(五个段)3.感性理解一下虚拟地址空间&#xf…

【C++修炼之路】C++入门(上)

👑作者主页:进击的安度因 🏠学习社区:进击的安度因(个人社区) 📖专栏链接:C修炼之路 文章目录一、前言二、第一个 C 程序三、C 关键字(C98)四、命名空间1、命名空间的定义2、命名空间…

C++ Prime课后习题第一章编程

编程一个C程序&#xff0c;它显示您的姓名和地址。#include <iostream>int stonetolb(int); int main() {using namespace std;cout << "zzz ";cout << "闵行"<<endl;return 0; }编写一个程序&#xff0c;要求用户输入一个以long…

3台机器配置hadoop集群_Hadoop+Hbase 分布式集群架构

安装搭建Hadoop1、 配置说明本次集群搭建共三台机器&#xff0c;具体说明下&#xff1a;主机名IP说明nn01192.168.1.51DataNode、NodeManager、ResourceManager、NameNodedn01192.168.1.52DataNode、NodeManager、SecondaryNameNodedn02192.168.1.53DataNode、NodeManager2 、安…