更多内容关注微信公众号:fullstack888

昨天很多同学在后台问,为什么Update是二阶段提交?紧接上文,我们了解了:深入理解Mysql执行过程及执行顺序。今天我们主要分析一下update语句是怎么执行的呢?

假设现在有一个表,只有两个字段:

  • 一个主键字段 id

  • 一个整型字段c

如果需要我们将id=2这一行的字段c值加1,SQL语句是这样的:

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

可以确定的是,查询语句的那一套流程,更新语句也是会走一遍。

首先连接器构建连接,连接器连接之后,如果是8.0之前的MySQL的话,应该还是会先去匹配一下查询缓存,然后发现没有命中这条查询语句。接着分析器会通过词法和语法解析知道这是一条更新语句。优化器决定要使用 ID 这个索引。然后,执行器负责具体执行,找到这一行,然后更新。再分析更新操作具体是如何实现之前,我们先来了解一个场景:

我们经营了一家饭店。饭店开张,客人会有赊账,还账,直接付账的情况,对应的掌柜的就需要记账,需要查账,修改账本上的赊账金额,或者删除某个赊账金额。对应的就正好是MySQL里面的增删改查操作。

客人不多时,掌柜的可以直接拿着账本去修改。但是客人很多,账本很厚的时候,掌柜的直接去修改账本就会影响做生意。所以聪明的掌柜的除了账本之外,还会有一个粉板,粉板上记录着当天都谁来还账了,谁来赊账,等到饭店打烊的时候,再根据粉板上记录的内容去改账本上的内容。

在 MySQL 里也有这个问题,如果每一次的更新操作都需要写进磁盘,然后磁盘也要找到对应的那条记录,然后再更新,整个过程 IO 成本、查找成本都很高。为了解决这个问题,MySQL 的设计者就用了类似酒店掌柜粉板的思路来提升更新效率。引入了两个日志。redo log(重做日志)和 binlog(归档日志)这也是我们今天需要 主要了解的主要内容。

上面的这种操作叫做WAL 技术。WAL 的全称是 Write-Ahead Logging(写前日志记录),它的关键点就是先写日志,再写磁盘。

InnoDb引擎日志:redo  log

重做日志

作用:确保事务的持久性。防止在发生故障的时间点,尚有脏页未写入磁盘,在重启mysql服务的时候,根据redo log进行重做,从而达到事务的持久性这一特性。

内容:物理格式的日志,记录的是物理数据页面的修改的信息,其redo log是顺序写入redo log file的物理文件中去的。

结合着我们今天的更新语句来说的话,当有一条记录需要更新的时候,InnoDB 引擎就会先把记录写到 redo log(粉板)里面,并更新内存,这个时候更新就算完成了。同时,InnoDB 引擎会在适当的时候,将这个操作记录更新到磁盘里面,而这个更新往往是在系统比较空闲的时候做,这就像打烊以后掌柜做的事。

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

与此类似,InnoDB 的 redo log 是固定大小的,比如可以配置为一组 4 个文件,每个文件的大小是 1GB,那么这块“粉板”总共就可以记录 4GB 的操作。从头开始写,写到末尾就又回到开头循环写,之前的记录就会被擦出掉。如下面这个图所示。

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

如图所示只有被擦除过的区域才能继续书写,也就是write pos 和 checkpoint 之间的那部分空着的区域,是可以用来记录新的操作。如果 write pos 追上 checkpoint,表示“粉板”满了,这时候不能再执行新的更新,得停下来先擦掉一些记录,把 checkpoint 推进一下。

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

注意这里仅仅是之前提交的记录不会丢失,我们都知道数据库的操作都涉及到事务,想要保证我们的事务完全正确,操作的记录和数据库数据保持一致,单单一个redo log是不行的,还需要另一个日志binlog。

server层日志:binlog

归档日志(二进制日志)

作用:用于复制,在主从复制中,从库利用主库上的binlog进行重播,实现主从同步。

用于数据库的基于时间点的还原。

内容:逻辑格式的日志,可以简单认为就是执行过的事务中的sql语句。

但又不完全是sql语句这么简单,而是包括了执行的sql语句(增删改)反向的信息,也就意味着delete对应着delete本身和其反向的insert;update对应着update执行前后的版本的信息;insert对应着delete和insert本身的信息。

形式:binlog 有三种模式:Statement(基于 SQL 语句的复制)、Row(基于行的复制) 以及 Mixed(混合模式)

两种日志有以下三点不同:

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

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

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

两阶段提交

有了对这两个日志的概念性理解,我们再来看执行器和 InnoDB 引擎在执行这个简单的 update 语句时的内部流程。

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

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

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

  • 执行器生成这个操作的 binlog,并把 binlog 写入磁盘。

  • 执行器调用引擎的提交事务接口,引擎把刚刚写入的 redo log 改成提交(commit)状态,更新完成。

放出 update 语句的执行流程图,图中浅色框表示是在 InnoDB 内部执行的,深色框表示是在执行器中执行的。

上面执行步骤中将 redo log 的写入拆成了两个步骤:prepare 和 commit,这就是"两阶段提交"。他的目的是为了让两份日志之间的逻辑一致。

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

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

先写 redo log 后写 binlog。假设在 redo log 写完,binlog 还没有写完的时候,MySQL 进程异常重启。由于我们前面说过的,redo log 写完之后,系统即使崩溃,仍然能够把数据恢复回来,所以恢复后这一行 c 的值是 1。但是由于 binlog 没写完就 crash 了,这时候 binlog 里面就没有记录这个语句。因此,之后备份日志的时候,存起来的 binlog 里面就没有这条语句。然后你会发现,如果需要用这个 binlog 来恢复临时库的话,由于这个语句的 binlog 丢失,这个临时库就会少了这一次更新,恢复出来的这一行 c 的值就是 0,与原库的值不同。

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

可以看到,如果不使用“两阶段提交”,那么数据库的状态就有可能和用它的日志恢复出来的库的状态不一致。简单点说,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 不丢失。

两阶段提交是跨系统维持数据逻辑一致性时常用的一个方案,即使不做数据库内核开发,日常开发中也有可能会用到。

- END -

推荐阅读:

深入理解Mysql执行过程及执行顺序

你真正思考过什么是架构吗?

分表分页/跨库分页为什么这么难?

墙裂推荐:灰常好用的画图工具

网易计费系统架构升级之路

NoOps 来了,DevOps 工程师的未来在何方?

关注:fullstack888

学习架构知识

互联网后端架构

update语句的执行过程相关推荐

  1. oracle+执行变量语句,ORACLE sql 语句的执行过程(SQL性能调整)

    第1章 SQL语句处理的过程 在调整之前我们需要了解一些背景知识,只有知道这些背景知识,我们才能更好的去调整sql语句. 本节介绍了SQL语句处理的基本过程,主要包括: · 查询语句处理 · DML语 ...

  2. 一条SQL查询语句的执行过程,一张图说清SQL查询语句执行过程

    一张图说明 一条SQL查询语句的执行过程 一条sql语句从发送到数据库到它执行完成并返回结果,主要经历以下几个过程: 连接器->查询缓存(如果开启了查询缓存,则会经过这一步,但是大多数情况下都是 ...

  3. mysql基础架构(一条update语句如何执行)

    update语句如何执行? 一.流程分析 二.重要的日志模块 1.redo log 2.binlog 3.两阶段提交 三.小结 一.流程分析 与查询流程不一样的是,更新流程涉及,两个重要的日志模块,r ...

  4. C语言中for语句的执行过程是什么?

    C语言中for语句的执行过程是: for语句的一般形式为:for(单次表达式;条件表达式;末尾循环体){中间循环体:}. for循环执行时,会先判断条件表达式是否成立,如果条件成立则执行中间循环体,执 ...

  5. 执行计划 分析一条sql语句的效率 mysql_MySQL中一条SQL语句的执行过程

    MySQL中一条SQL语句的执行过程 发布时间:2018-11-24 18:35, 浏览次数:390 , 标签: MySQL SQL 查询语句的执行顺序: 1.客户端通过TCP连接发送连接请求到mys ...

  6. (111)FPGA面试题-介绍Verilog 块语句fork-join执行过程

    1.1 FPGA面试题-介绍Verilog 块语句fork-join执行过程 1.1.1 本节目录 1)本节目录: 2)本节引言: 3)FPGA简介: 4)FPGA面试题-介绍Verilog 块语句f ...

  7. (110)FPGA面试题-介绍Verilog块语句begin-end执行过程

    1.1 FPGA面试题-介绍Verilog块语句begin-end执行过程 1.1.1 本节目录 1)本节目录: 2)本节引言: 3)FPGA简介: 4)FPGA面试题-介绍Verilog块语句beg ...

  8. for语句的执行过程_深入学习MySQL 01 一条查询语句的执行过程

    在学习SpringCloud的同时,也在深入学习MySq中,听着,,看着<高性能MySQL>,本系列文章是本人学习过程的总结,水平有限,仅供参考,若有不对之处或有啥建议都可与我联系,感谢! ...

  9. C语言条件循环语句执行步骤,C语言中for语句的执行过程是什么?

    C语言中for语句的执行过程是:1.会先判断条件表达式是否成立,如果条件成立则执行中间循环体,执行完中间循环体后接着执行末尾循环体 :2.在执行完末尾循环体后对条件表达式再次判断,若条件还成立,则继续 ...

最新文章

  1. gsonformat安装怎么使用_车载蓝牙充电器怎么安装使用?如何运用
  2. HTML中文字布局,HTML文字布局
  3. 执行 java -jar xxx.jar 是不是创建进程问题
  4. python目前版本强势英雄_王者荣耀目前版本什么英雄强势?
  5. 美国虚拟主机大打安全牌争抢国内高端外贸主机市场
  6. Windows7修改hosts提示:您没有权限在此位置中保存文件
  7. 微软已确认放弃Windows 10X操作系统 新功能下放
  8. JavaScript如何进行文件上传
  9. qq表情包html插件,程序员用jQuery写QQ表情插件,代码思路瞬间爆炸
  10. java代码混淆-ProGuard
  11. word删除空白页的6种方法和技巧
  12. 做到这一点,帮你每年多赚10万!
  13. input输入框添加键盘事件
  14. 几个经典差动放大器应用电路详解
  15. 2018之后的Unity3d制作AR教程
  16. python机器语言直接用二进制代码表达指令_尔雅慕课搜题app,超星尔雅考试搜题,超星慕课查题app,学堂云搜题...
  17. 只需一次向前推导,深度神经网络可视化方法来了!(ECCVW 2022)
  18. 信息收集之——子域信息
  19. 【编译原理】活动记录
  20. 数据库原理与应用笔记(一):数据库绪论

热门文章

  1. 3d建模师工资高吗?3d建模师未来发展前景怎么样?
  2. November, 19
  3. 无线网络技术—无线蓝牙技术
  4. RequestMapping的用法(完整)
  5. 奈雪的茶上市了,资本愿意砸钱,营销策略做的好,猪也能上树
  6. app专项测试之电量测试
  7. 英语年份有日期的读法
  8. 音视频播放 via Media Foundation II
  9. 老公出轨还放言天下男人都偷吃
  10. 【观察】西部数据创新存储架构,释放开放计算新力量