MySQL高阶知识点(一)一条SQL【更新】语句是如何执行的

一条SQL【更新】语句是如何执行的
首先,可以确定的说,【查询】语句的那一套流程,【更新】语句也是同样会走一遍,与查询流程不一样的是,
更新语句涉及到【事务】,就必须保证事务的四大特性:ACID,
所以更新流程涉及到两个重要的日志模板:

  • redo log(重做日志)
  • binlog(归档日志)

1 redo log

首先redo log日志是innodb引擎特有,这也是innodb引擎成为mysql最主流引擎的主要原因。

《孔乙己》这篇文章,酒店掌柜有一个粉板,专门用来记录客人的赊账记录。如果赊账的人不多,那么他可以把顾客名和账目写在板上。但如果赊账的人多了,粉板总会有记不下的时候,这个时候掌柜一定还有一个专门记录赊账的账本。

如果有人要赊账或者还账的话,掌柜一般有两种做法:
一种做法是直接把账本翻出来,把这次赊的账加上去或者扣除掉;
另一种做法是先在粉板上记下这次的账,等打烊以后再把账本翻出来核算。

在生意红火柜台很忙时,掌柜一定会选择后者,因为前者操作实在是太麻烦了。首先,你得找到这个人的赊账总额那条记录。你想想,密密麻麻几十页,掌柜要找到那个名字,可能还得带上老花镜慢慢找,找到之后再拿出算盘计算,最后再将结果写回到账本上。这整个过程想想都麻烦。相比之下,还是先在粉板上记一下方便。你想想,如果掌柜没有粉板的帮助,每次记账都得翻账本,效率是不是低得让人难以忍受?

同样,在 MySQL 里也有这个问题,如果每一次的更新操作都需要写进磁盘,然后磁盘也要找到对应的那条记录,然后再更新,整个过程 IO 成本、查找成本都很高。

为了解决这个问题,MySQL 的设计者就用了类似酒店掌柜粉板的思路来提升更新效率。

先写日志,再写磁盘

而粉板和账本配合的整个过程,其实就是 MySQL 里经常说到的 WAL 技术,WAL 的全称是 Write-Ahead Logging,它的关键点就是先写日志,再写磁盘,也就是先写粉板,等不忙的时候再写账本。

具体来说,当有一条记录需要更新的时候,InnoDB 引擎就会先把记录写到 redo log(粉板)里面,并更新内存,这个时候更新就算完成了。

同时,InnoDB 引擎会在适当的时候,将这个操作记录更新到磁盘里面,而这个更新往往是在系统比较空闲的时候做,这就像打烊以后掌柜做的事。
如果今天赊账的不多,掌柜可以等打烊后再整理。

但如果某天赊账的特别多,粉板写满了,又怎么办呢?
这个时候掌柜只好放下手中的活儿,把粉板中的一部分赊账记录更新到账本中,然后把这些记录从粉板上擦掉,为记新账腾出空间。

与此类似,InnoDB 的 redo log 是固定大小的,比如可以配置为一组 4 个文件,每个文件的大小是 1GB,那么这块“粉板”总共就可以记录 4GB 的操作。
从头开始写,写到末尾就又回到开头循环写,如下面这个图所示。
在这里插入图片描述
write pos 是当前记录的位置,一边写一边后移,写到第 3 号文件末尾后就回到 0 号文件开头。

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

write pos 和 checkpoint 之间的是“粉板”上还空着的部分,可以用来记录新的操作。
如果 write pos 追上 checkpoint,表示“粉板”满了,这时候不能再执行新的更新,得停下来先擦掉一些记录,把 checkpoint 推进一下。

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

2 binlog

redo log 是 InnoDB 引擎特有的日志,而 Server 层也有自己的日志,称为 binlog(归档日志)。

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

因为最开始 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 文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。

执行流程

接下来,我们看一条更新sql的整体执行流程:

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

执行器先找引擎取 ID=2 这一行。
ID 是主键,引擎直接用树搜索找到这一行。

如果 ID=2 这一行所在的数据页本来就在内存中,就直接返回给执行器;
否则,需要先从磁盘读入内存,然后再返回。

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

redo log 记录更新操作 – prepare

引擎将这行新数据更新到内存中,同时将这个更新操作记录到 redo log 里面,此时 redo log 处于 prepare 状态。

然后告知执行器执行完成了,随时可以提交事务。
[innodb–>server][记录下的是修改数据页的操作–正在处理中,prepare]

binlog将更新操作写入磁盘

执行器生成这个操作的 binlog,并把 binlog 写入磁盘。
[server–>innodb][记录的是:update T … 到binlog,磁盘]

redo log 记录更新操作 – commit

执行器调用引擎的提交事务接口,引擎把刚刚写入的 redo log 改成提交(commit)状态,更新完成。
[innodb][记录下的是修改数据页的操作–处理已完成,commit]

这个 update 语句的执行流程图如下:
在这里插入图片描述

两阶段提交

通过上面可以发现,将 redo log 的写入拆成了两个步骤:prepare 和 commit,这就是"两阶段提交”。

为什么日志需要“两阶段提交”?
这里不妨用反证法来进行解释。由于 redo log 和 binlog 是两个独立的逻辑,如果不用两阶段提交,要么就是

  • 写完 redo log 再写 binlog,
  • 或者采用反过来的顺序:先写binlog 再写 redo log

我们看看这两种方式会有什么问题。

先写 redo log 后写 binlog。

假设在 redo log 写完,binlog 还没有写完的时候,MySQL 进程异常重启。
由于我们前面说过的,redo log 写完之后,系统即使崩溃,仍然能够把数据恢复回来,所以恢复后这一行 c 的值是 1。
但是由于 binlog 没写完就 crash 了,这时候 binlog 里面就没有记录这个语句(update …)。
因此,之后备份日志的时候,存起来的 binlog 里面就没有这条语句。

然后你会发现,如果需要用这个 binlog 来恢复临时库的话,由于这个语句的 binlog 丢失,这个临时库就会少了这一次更新,恢复出来的这一行 c 的值就是 0,与原库的值不同(在没有crash之前,是记录的1,重启后,binlog没有这条sql,所以为0)。

先写 binlog 后写 redo log。

如果在 binlog 写完之后 crash,由于 redo log 还没写,崩溃恢复以后这个事务无效,所以这一行 c 的值是 0。
但是 binlog 里面已经记录了“把 c 从 0 改成 1”这个日志。
所以,在之后用 binlog 来恢复的时候就多了一个事务出来,恢复出来的这一行 c 的值就是 1,与原库的值不同(数据库原先是0,系统重启后读取binlog,恢复的数据多了一条,设置为1)。

两阶段提交是分布式事务一致性的一种解决方案。

redo log 用于保证 crash-safe 能力。

innodb_flush_log_at_trx_commit 这个参数设置成 1 的时候,表示每次事务的 redo log 都直接持久化到磁盘。这样可以保证 MySQL 异常重启之后数据不丢失。

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

  • innodb_flush_log_at_trx_commit : redo log 持久化
  • sync_binlog : binlog 持久化

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

k8s 滚动更新控制(一)

在传统的应用升级时,通常采用的方式是先停止服务,然后升级部署,最后将新应用启动。这个过程面临一个问题,就是在某段时间内,服务是不可用的,对于用户来说是非常不友好的。而kubernetes滚动更新,…

jacoco功能测试-代码覆盖率

1、下载 jacoco 官网地址:EclEmma - JaCoCo Java Code Coverage Library 2、拷贝 jar 包 下载好后,找到这两个文件,然后找到被测项目 3、启动 jacocoagent,监控被测项目 java -javaagent:jacocoagent.jarincludes*,outputtcp…

Filament for Android 编译搭建(基于Ubuntu20.04系统)

一、Filament 源代码下载 github下载地址: 2、安装clang 我是直接安装clang-10 Ubuntu 20.04 ,sudo apt install clang 命令默认就是clang-10 $sudo apt-get install clang-10 # 安装 AST.h 等头文件 $sudo apt-get install libclang-10-dev $sudo …

【Linux操作系统】文件描述符fd

🔥🔥 欢迎来到小林的博客!!       🛰️博客主页:✈️林 子       🛰️博客专栏:✈️ Linux之路       🛰️社区 :✈️ 进步学堂       &#x1…

使用logback异步打印日志

文章目录 一、介绍二、运行环境三、演示项目1. 接口2. 日志配置文件3. 效果演示4. 异步输出验证 四、异步输出原理五、其他参数配置六、源码分析1. 同步输出2. 异步输出 七、总结 一、介绍 对于每一个开发人员来说,在业务代码中添加日志是至关重要的,尤…

docker基本使用方法

docker使用 1. Docker 介绍 Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。Docker 使您能够将应用程序与基础架构分开,从而可以快速交付软件。通过利用 …

Oracle 开发篇+Java通过DRCP访问Oracle数据库

标签:DRCP、Database Resident Connection Pooling、数据库驻留连接池释义:DRCP(全称Database Resident Connection Pooling)数据库驻留连接池(Oracle自己的数据库连接池技术) ★ Oracle开启并配置DRCP sq…

神码ai伪原创文章生成器软件【php源码】

大家好,本文将围绕python二级用哪个版本的软件展开说明,二级python 值不值得考是一个很多人都想弄明白的事情,想搞清楚python二级用什么软件需要先了解以下几个事情。 火车头采集ai伪原创插件截图: 问题一:安装python…

java+springboot+mysql智能社区管理系统

项目介绍: 使用javaspringbootmysql开发的社区住户综合管理系统,系统包含超级管理员、管理员、住户角色,功能如下: 超级管理员:管理员管理;住户管理;房屋管理(楼栋、房屋&#xff…

代码详解——Transformer

文章目录 整体架构Modules.pyScaledDotProductAttention SubLayers.pyMultiHeadAttentionPositionwiseFeedForward Layers.pyEncoderLayerDecoderLayer Models.pyget_pad_maskget_subsequent_maskPositionalEncodingEncoderDecoderTransformer 整体架构 源码地址(py…

电商3D产品渲染简明教程

3D 渲染让动作电影看起来更酷,让建筑设计变得栩栩如生,现在还可以帮助营销人员推广他们的产品。 从最新的《阿凡达》电影到 Spotify 的上一次营销活动,3D 的应用让一切变得更加美好。 在营销领域,3D 产品渲染可帮助品牌创建产品的…

Docker+rancher部署SkyWalking8.5并应用在springboot服务中

1.Skywalking介绍 Skywalking是一个国产的开源框架,2015年有吴晟个人开源,2017年加入Apache孵化器,国人开源的产品,主要开发人员来自于华为,2019年4月17日Apache董事会批准SkyWalking成为顶级项目,支持Jav…

Kafka消息队列学习(一)

文章目录 概述核心概念生产者示例同步 / 异步发送消息生产者参数配置ack-确认机制retries - 重试次数compression_type - 消息压缩类型 分区机制分区策略 消费者消息有序性提交和偏移量偏移量提交方式手动提交 高可用设计 SpringBoot集成Kafka基本使用传递对象消息 概述 核心概…

2023企业微信0day漏洞复现以及处理意见

2023企业微信0day漏洞复现以及处理意见 一、 漏洞概述二、 影响版本三、 漏洞复现小龙POC检测脚本: 四、 整改意见 免责声明:请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#x…

Arduino+esp32学习笔记

学习目标: 使用Arduino配置好蓝牙或者wifi模块 学习使用python配置好蓝牙或者wifi模块 学习内容(笔记): 一、 Arduino语法基础 Arduino语法是基于C的语法,C又是c基础上增加了面向对象思想等进阶语言。那就只记录没见过的。 单多…

Mysql in 查询的奇怪方向

Mysql in 查询的奇怪方向 关于表字段存储的数据为 num1,num2,num3时, 还要通过多个num1,num2入参针对该字段进行查询 建表语句 CREATE TABLE test (test_ids varchar(100) DEFAULT NULL COMMENT 保存ids 以逗号分隔 ) ENGINEInnoDB;数据项 查询语句 SELECT test_ids FROM t…

Android之版本号、版本别名、API等级对应关系(全)(一百六十二)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生…

数据结构:选择排序

简单选择排序 选择排序是一种简单直观的排序算法。首先在未排序序列中找到最大(最小)的元素,存放到排序学列的其实位置,然后在剩余的未排序的元素中寻找最小(最大)元素,存放在已排序序列的后面…

NLP文本分类

NLP文本分类 落地实战五大利器!_kaiyuan_sjtu的博客-CSDN博客https://zhuanlan.zhihu.com/p/432619164 https://github.com/alibaba/EasyNLP/blob/master/README.cn.md

【5G 核心网】5G 多PDU会话锚点技术介绍

博主未授权任何人或组织机构转载博主任何原创文章,感谢各位对原创的支持! 博主链接 本人就职于国际知名终端厂商,负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作,目前牵头6G算力网络技术标准研究。 博客…