MySQL中一条update语句是如何执行的


Posted in MySQL onMarch 16, 2022

前言

?上一篇文章说完MySQL的事务和锁了,这次来详细介绍一下在MySQL中一条更新语句的详细执行流程 (本文无特殊说明均是采用Innodb存储引擎)。

前期准备

⭐⭐首先创建一张表,然后插入三条数据:

CREATE TABLE T(
	ID int(11) NOT NULL AUTO_INCREMENT,
	c int(11) NOT NULL,
	PRIMARY KEY (ID)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='测试表';

INSERT INTO T(c) VALUES (1), (2), (3);

让后执行更新操作:

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

在说更新操作前,大家先来看一下sql语句在MySQL中的执行流程~

?SQL语句的执行过程

MySQL中一条update语句是如何执行的

??‍?如图所示:MySQL数据库主要分为两个层级:服务层存储引擎层服务层:server层包括连接器、查询缓存、分析器、优化器、执行器,包括大多数MySQL中的核心功能所有跨存储引擎的功能也在这一层实现,包括 存储过程、触发器、视图等。 存储引擎层:存储引擎层包括MySQL常见的存储引擎,包括MyISAM、InnoDB和Memory等,最常用的是InnoDB,也是现在MySQL的默认存储引擎。

server层中的组件介绍✨✨✨

  1. 连接器: 需要MySQL客户端登录,需要一个 连接器 来连接用户和MySQL数据库,“mysql -u 用户名 -p 密码” 进行MySQL登录,在完成 TCP握手 后,连接器会根据输入的用户名和密码验证登录身份。
  2. 查询缓存: MySQL在得到一个执行请求后,会首先去 查询缓存 中查找,是否执行过这条SQL语句,之前执行过得语句以及结果会以 key-value对的形式,放在内存中。key是查询语句,value是查询的结果。如果通过key能够查找到这条SQL语句,直接返回SQL的执行结果。若不存在缓存中,就会继续后面的执行阶段。执行完成后,执行结果就会被放入查询缓存中。优点是效率高。但是查询缓存不建议使用, 因为在MySQL中对某张表进行了更新操作,那么所有的查询缓存就会失效,对于更新频繁的数据库来说,查询缓存的命中率很低。需要注意:在MySQL8.0版本,查询缓存功能就删除了,不存在查询缓存的功能了
  3. 分析器: 分为词法分析和语法分析
    1. 词法分析: 首先,MySQL会根据SQL语句进行解析,分析器会先做 词法分析,你写的SQL就是由多个字符串和空格组成的一条SQL语句,MySQL需要识别出里面的字符串是什么,代表什么。
    2. 语法分析: 然后进行 语法分析, 根据词法分析的结果,语法分析器会根据语法规则,判断输入的这个SQL语句是否满足MySQL语法。如果SQL语句不正确,就提示:You have an error in your SQL suntax
  4. 优化器: 经过分析器分析后,SQL就合法了,但在执行之前,还需要进行优化器的处理,优化器会判断使用了哪种索引,使用哪种连接,优化器的作用 就是确定效率最高的执行方案。
  5. 执行器: 在执行阶段,MySQL首先会判断有没有执行语句的权限,若无权限,返回没有权限的错误;若有权限,就打开表继续执行。打开表时,执行器会根据标的引擎定义,去使用该引擎提供的接口,对于有索引的表,执行的逻辑类似。

了解完SQL语句的执行流程我们接下来详细分析一下上面update T set c=c+1 where ID=2;是如何执行的。

?Update语句分析

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

在执行update更新操作的时候,跟这个表有关的查询缓存会失效,所以这条语句就会把表 T 上所有缓存结果都清空。接下来,分析器会经过语法分析和词法分析,知道了这是一条更新语句后,优化器决定要使用哪一个索引,然后执行器负责具体的执行,先找到这一行,然后做更新。

按照我们平常的思路,就是 找出这条记录,把它的值改好,保存就OK了 。但我们追究一下细节,由于涉及到修改数据,所以涉及到日志了。更新操作涉及到两个重要的日志模块。redo log(重做日志),bin log(归档日志)。MySQL中的这两个日志也是必学的。

redo log(重做日志)?

  • 在 MySQL 里,如果每一次的更新操作都需要写进磁盘,然后磁盘也要找到对应的那条记录,然后再更新,整个过程 IO 成本、查找成本都很高。
    MySQL里使用WAL(预写式日志)技术,WAL 的全称是 Write-Ahead Logging,它的关键点就是 先写日志,再写磁盘。
  • 具体来说,当有一条记录需要更新的时候,InnoDB 引擎就会先把记录写到 redo log里面,并更新内存,这个时候更新就算完成了。同时,InnoDB 引擎会在适当的时候,将这个操作记录更新到磁盘里面,而这个更新往往是在系统比较空闲的时候做。
  • InnoDB 的 redo log 是固定大小的,比如可以配置为一组 4 个文件,每个文件的大小是 1GB,那么总共就可以记录 4GB 的操作。从头开始写,写到末尾就又回到开头循环写。

听完上面对redo log日志的介绍后,小伙伴们可能会问:redo log日志存储在哪?, 数据库信息保存在磁盘上,redo log日志也保存在磁盘上,为什么要先写到redo log中再写到数据库中呢?,redo log日志如果存满数据了怎么办?等等。接下来就解答一下这些疑问。

redo log存储在哪里??

InnoDB引擎先把记录写到redo log 中,redo log 在哪,它也是在磁盘上,这也是一个写磁盘的过程, 但是与更新过程不一样的是,更新过程是在磁盘上随机IO,费时。 而写redo log 是在磁盘上顺序IO。效率要高。

redo log 空间是固定,那它会不会用完呢??

首先不用担心 redo log 会用完空间,因为它是循环利用的。例如 redo log 日志配置为一组4个文件,每个文件分别为1G。它写的流程如下图:

MySQL中一条update语句是如何执行的

简单总结一下: redo log日志是Innodb存储引擎特有的机制,可以用来应对异常恢复Crash-safe,redo可以保证mysql异常重启时,将未提交的事务回滚,已提交的事务安全落库。

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

binlog(归档日志)??‍♀️

redo log是innoDB 引擎特有的日志。而binlog是mysql server层的日志。

其实bin log日志出现的时间比redo log早,因为最开始MySQL是没有InnoDB存储引擎的,5.5之前是MyISAM。但是 MyISAM 没有 crash-safe 的能力,binlog 日志只能用于归档。而 InnoDB 是另一个公司以插件形式引入 MySQL 的,既然只依靠 binlog 是没有 crash-safe 能力的,所以 InnoDB 使用另外一套日志系统——也就是 redo log 来实现 crash-safe 能力。

redo log和bin log的总结?:

  • redo log是为了保证innoDB引擎的crash-safe能力,也就是说在mysql异常宕机重启的时候,之前提交的事务可以保证不丢失;(因为成功提交的事务肯定是写入了redo log,可以从redo log恢复)
  • bin log是归档日志,将每个更新操作都追加到日志中。这样当需要将日志恢复到某个时间点的时候,就可以根据全量备份+bin log重放实现。 如果没有开启binlog,那么数据只能恢复到全量备份的时间点,而不能恢复到任意时间点。如果连全量备份也没做,mysql宕机,磁盘也坏了,那就很尴尬了。。

redo log和bin log的区别?:

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

?InnoDB引擎部分在执行这个简单的update语句的时候的内部流程

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

MySQL中一条update语句是如何执行的

?手动用begin开启事务,然后执行update语句,再然后执行commit语句,那上面的update更新流程之前 哪些是update语句执行之后做的,哪些是commit语句执行之后做的?

事实上,redo log在内存中有一个redo log buffer,binlog 也有一个binlog cache.所以在手动开启的事务中,你执行sql语句,其实是写到redo log bufferbinlog cache中去的(肯定不可能是直接写磁盘日志,一个是性能差一个是回滚的时候不可能去回滚磁盘日志吧),然后当你执行commit的时候,首先要将redo log的提交状态游prepare改为commit状态,然后就要把binlog cache刷新到binlog日志(可能也只是flush到操作系统的page cache,这个就看你的mysql配置),redo log buffer刷新到redo log 日志(刷新时机也是可以配置的)。 如果你回滚的话,就只用把binlog cacheredo log buffer中的数据清除就行了。

?在update过程中,mysql突然宕机,会发生什么情况?

  1. 如果redolog写入了,处于prepare状态,binlog还没写入,那么宕机重启后,redolog中的这个事务就直接回滚了。
  2. 如果redolog写入了,binlog也写入了,但redolog还没有更新为commit状态,那么宕机重启以后,mysql会去检查对应事务在binlog中是否完整。如果是,就提交事务;如果不是,就回滚事务。 (redolog处于prepare状态,binlog完整启动时就提交事务,为啥要这么设计? 主要是因为binlog写入了,那么就会被从库或者用这个binlog恢复出来的库使用,为了数据一致性就采用了这个策略)

redo log和binlog是通过xid这个字段关联起来的

总结

到此这篇关于MySQL中一条update语句是如何执行的文章就介绍到这了,更多相关MySQL update语句执行内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

MySQL 相关文章推荐
解读MySQL的客户端和服务端协议
May 10 MySQL
mysql 8.0.24版本安装配置方法图文教程
May 12 MySQL
MySQL 8.0 之不可见列的基本操作
May 20 MySQL
MySQL 数据类型选择原则
May 27 MySQL
MySQL外键约束(FOREIGN KEY)案例讲解
Aug 23 MySQL
MySQL中datetime时间字段的四舍五入操作
Oct 05 MySQL
MySQL七种JOIN类型小结
Oct 24 MySQL
SQL注入详解及防范方法
Dec 06 MySQL
一文搞懂MySQL索引页结构
Feb 28 MySQL
数据分析数据库ClickHouse在大数据领域应用实践
Apr 03 MySQL
解决MySQL Varchar 类型尾部空格的问题
Apr 06 MySQL
MySQL提取JSON字段数据实现查询
Apr 22 MySQL
关于k8s环境部署mysql主从的问题
Mar 13 #MySQL
MYSQL如何查看进程和kill进程
Mar 13 #MySQL
一次SQL如何查重及去重的实战记录
Mar 13 #MySQL
面试提问mysql一张表到底能存多少数据
MySQL的索引你了解吗
面试中老生常谈的MySQL问答集锦夯实基础
浅谈如何保证Mysql主从一致
You might like
PHP 加密与解密的斗争
2009/04/17 PHP
hadoop常见错误以及处理方法详解
2013/06/19 PHP
php生成随机颜色方法汇总
2014/12/03 PHP
PHP实现QQ空间自动回复说说的方法
2015/12/02 PHP
在laravel中实现事务回滚的方法
2019/10/10 PHP
MacOS下PHP7.1升级到PHP7.4.15的方法
2021/02/22 PHP
HR vs CL BO3 第二场 2.13
2021/03/10 DOTA
jQeury淡入淡出需要注意的问题
2010/09/08 Javascript
javascript模版引擎-tmpl的bug修复与性能优化分析
2011/10/23 Javascript
巧用jquery解决下拉菜单被Div遮挡的相关问题
2014/02/13 Javascript
jQuery的animate函数学习记录
2014/08/08 Javascript
JQuery控制div外点击隐藏而div内点击不会隐藏的方法
2015/01/13 Javascript
js实现键盘Enter键提交表单的方法
2015/05/27 Javascript
JS实现不规则TAB选项卡效果代码
2015/09/16 Javascript
浅谈Node.js:Buffer模块
2016/12/05 Javascript
jQuery+PHP+Mysql实现抽奖程序
2020/04/12 jQuery
JS+jQuery实现注册信息的验证功能
2017/09/26 jQuery
vue实现仿淘宝结账页面实例代码
2017/11/08 Javascript
微信小程序icon组件使用详解
2018/01/31 Javascript
vue项目中使用Hbuilder打包app 设置沉浸式状态栏的方法
2018/10/22 Javascript
详解vue使用$http服务端收不到参数
2019/04/19 Javascript
微信小程序实现分享商品海报功能
2019/09/30 Javascript
vue-cli点击实现全屏功能
2020/03/07 Javascript
javascript实现简易计算器功能
2020/09/23 Javascript
[01:01:41]DOTA2-DPC中国联赛 正赛 PSG.LGD vs Magma BO3 第二场 1月31日
2021/03/11 DOTA
解决Scrapy安装错误:Microsoft Visual C++ 14.0 is required...
2017/10/01 Python
Python get获取页面cookie代码实例
2018/09/12 Python
pandas中apply和transform方法的性能比较及区别介绍
2018/10/30 Python
使用OpenCV实现道路车辆计数的使用方法
2020/07/15 Python
寄语是什么意思
2014/04/10 职场文书
节约用水演讲稿
2014/05/21 职场文书
国家领导干部党的群众路线教育实践活动批评与自我批评材料
2014/09/23 职场文书
运动会广播稿200字(10篇)
2014/10/12 职场文书
2014年乡镇卫生院工作总结
2014/11/24 职场文书
2015年电话销售工作总结范文
2015/04/20 职场文书
基于angular实现树形二级表格
2021/10/16 Javascript