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

news2024/10/7 2:18:40

一条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 持久化

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

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

相关文章

vite打包报错

先把报错信息附上 解决: 在报错的文件里加上ts就可以了

Python python文件打包exe文件

首先安装PyInstaller,在PyCharm终端窗口输入命令: pip install PyInstaller安装完成后,在输入命令: pyinstaller -F /Users/sunshiyu/Desktop/PYTHON/demo1.pydemo1.py是我创建的一个简单的Python文件,代码如下&#x…

数据结构:堆的应用(堆排序和topk问题)

个人主页 : 个人主页 个人专栏 : 《数据结构》 《C语言》 文章目录 堆排序建堆堆的删除思想排序代码实现 top k 问题思路代码实现 总结 堆排序 堆排序即是 先将数据建堆,再利用堆删除的思想来排序。 将待排序数组建堆将堆顶数据与数组尾部数…

【python】爬取豆瓣电影Top250(附源码)

前言 在网络爬虫的开发过程中,经常会遇到需要处理一些反爬机制的情况。其中之一就是网站对于频繁访问的限制,即IP封禁。为了绕过这种限制,我们可以使用代理IP来动态改变请求的来源IP地址。在本篇博客中,将介绍如何使用代理IP的技术…

RHEL 7配置HAProxy实现Web负载均衡

一、测试环境HAProxy: 主机名:RH7-HAProxy IP地址:192.168.10.20 操作系统:Red Hat Enterprise Linux Server release 7.2 (Maipo)最小化安装 防火墙与SELinux:关闭 安装的服务:HAProxy-1.5.14 WEB01: 主…

[管理与领导-12]:IT基层管理者 - 绩效面谈 - 如何面谈,遇到问题员工怎么办?

目录 前言: 第1章 问题现象 第一:面谈没效果 第二:问题没解决 第三:双方都不满 第2章 背后原因 1.1 面谈变成了训话:引导变成训话 1.2 面谈变成了扯皮:立足未来变成纠缠过去 1.3 面谈变成了双方较…

vite4+vue3:从0到1搭建vben后台管理系统(五)-封装属于自己的form组件

日常业务开发中的,避免不了的要接触到表单开发,那么我们有必要了解表单的深入使用方法,及封装出适合自己业务的自定义表单组件,效果如下: 不是用ele和antdvue框架,实现自己的表单组件!!! ValidateForm组件封装 <template><div class="validate-form…

c++学习(多线程)[33]

thread 本质封装操作系统的库 事实证明&#xff0c;两个线程在cpu中交错运行 thread传参为模板参数&#xff0c;应用折叠&#xff0c;都会变成左值&#xff0c;所以count还是0 sleep_until 在C中&#xff0c;没有直接的sleep_until函数&#xff0c;但可以使用std::th…

c++ 有元

友元分为两部分内容 友元函数友元类 友元函数 问题&#xff1a;当我们尝试去重载operator<<&#xff0c;然后发现没办法将operator<<重载成成员函数。因为cout的输出流对象和隐含的this指针在抢占第一个参数的位置。this指针默认是第一个参数也就是左操作 数了。…

dbm与mw转换

功率值10^(dBm值/10)&#xff0c;单位mW。 对于-5dBm&#xff0c;其功率值为0.3162 mW。 dBm 10 * lg(mW&#xff09;

C++ STL vector 模拟实现

✅<1>主页&#xff1a;我的代码爱吃辣 &#x1f4c3;<2>知识讲解&#xff1a;C之STL &#x1f525;<3>创作者&#xff1a;我的代码爱吃辣 ☂️<4>开发环境&#xff1a;Visual Studio 2022 &#x1f4ac;<5>前言&#xff1a;上次我们已经数字会用…

创建多图层叠加效果的背景与人物图像

引言&#xff1a; 在现代应用程序开发中&#xff0c;图形资源的使用是非常常见的&#xff0c;特别是在用户界面设计中。通过使用TImageList和TGlyph组件的组合&#xff0c;我们可以实现令人印象深刻的多图层叠加效果。本文将介绍如何使用这两个组件来创建背景和人物的多图层叠加…

doubletrouble靶机通关详解

信息收集 漏洞发现 扫目录 发现secret路径 里面有个图 qdPM9.1 网上找找exp 反弹shell http://192.168.0.107//uploads/users/632300-backdoor.php?cmdecho "<?php eval(\$_POST[1]);?>" > 1.php 蚁剑连上去传php-reverse-shell.php 提权 优化shell…

企业微信爆出漏洞,公司员工被迫摸鱼

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;对网络安全感兴趣的小伙伴可以关注专栏《网络安全入门到精通》 昨晚加班好好的&#xff0c;突然接到公司通知&…

不可能,绝对不可能

前言 有 2 个月未更了&#xff0c;读者朋友微信留言&#xff1a;“亮哥&#xff0c;最近是不是颓了&#xff1f;好久未更了” 我随即回复&#xff1a; 没想到这时兄弟发来了&#xff1a; 好吧&#xff0c;给大家汇报下近况&#xff0c;不枉大家一直激励我前行。 项目管理 前段时…

MySQL分表实现上百万上千万记录分布存储的批量查询设计模式

我们知道可以将一个海量记录的 MySQL 大表根据主键、时间字段&#xff0c;条件字段等分成若干个表甚至保存在若干服务器中。唯一的问题就是跨服务器批量查询麻烦&#xff0c;只能通过应用程序来解决。谈谈在Java中的解决思路。其他语言原理类似。这里说的分表不是 MySQL 5.1 的…

STM32入门学习之定时器PWM输出

1.脉冲宽度调制PWM(Pulse Width Modulation)是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。PWM可以理解为高低电平的占空比&#xff0c;即输出高电平时间与低电平时间的比值。PWM的应用是否广泛&#xff0c;比如在步进电机的控制中&#xff0c;可以通过P…

WebRTC本地视频通话使用ossrs服务搭建

iOS开发-ossrs服务WebRTC本地视频通话服务搭建 之前开发中使用到了ossrs&#xff0c;这里记录一下ossrs支持的WebRTC本地服务搭建。 一、ossrs是什么&#xff1f; ossrs是什么呢&#xff1f; SRS(Simple Realtime Server)是一个简单高效的实时视频服务器&#xff0c;支持RTM…

【佳佳怪文献分享】通过引导学会行走: 动态环境中的感知四足运动

标题&#xff1a;Learning to Walk by Steering: Perceptive Quadrupedal Locomotion in Dynamic Environments 作者&#xff1a;Mingyo Seo , Ryan Gupta , Yifeng Zhu , Alexy Skoutnev , Luis Sentis , and Yuke Zhu 来源&#xff1a;2023 IEEE International Conference …

Titanic--细节记录二

merge、join以及concat的方法的不同以及相同 相同之处&#xff1a;都用于合并数据。 不同之处&#xff1a; merge主要是基于列的合并。join主要是基于索引&#xff08;行标签&#xff09;的合并。concat可以沿任意轴合并&#xff0c;更灵活。 import pandas as pddf1 pd.Da…