一条SQL语句的前世今生

news2024/11/8 18:08:55

文章目录

  • MySQL 基础架构分析
  • 语句分析
    • 查询语句
    • 更新语句
  • 总结

本篇文章会分析下一个 SQL 语句在 MySQL 中的执行流程,包括 SQL 的查询在 MySQL 内部会怎么流转,SQL 语句的更新是怎么完成的。

MySQL 基础架构分析

下图是 MySQL 的一个简要架构图,从下图你可以很清晰的看到用户的 SQL 语句在 MySQL 内部是如何执行的。

先简单介绍一下下图涉及的一些组件的基本作用帮助大家理解这幅图,在后面会详细介绍到这些组件的作用。

  • 连接器: 身份认证和权限相关(登录 MySQL 的时候)。
  • 查询缓存: 执行查询语句的时候,会先查询缓存(MySQL 8.0 版本后移除,因为这个功能不太实用)。
  • 分析器: 没有命中缓存的话,SQL 语句就会经过分析器,分析器说白了就是要先看你的 SQL 语句要干嘛,再检查你的 SQL 语句语法是否正确。
  • 优化器: 按照 MySQL 认为最优的方案去执行。
  • 执行器: 执行语句,然后从存储引擎返回数据。

在这里插入图片描述

简单来说 MySQL 主要分为 Server 层和存储引擎层:

  • Server 层:主要包括连接器、查询缓存、分析器、优化器、执行器等,所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图,函数等,还有一个通用的日志模块 binlog 日志模块。
  • 存储引擎: 主要负责数据的存储和读取,采用可以替换的插件式架构,支持 InnoDB、MyISAM、Memory 等多个存储引擎,其中 InnoDB 引擎有自有的日志模块 redolog 模块。现在最常用的存储引擎是 InnoDB,它从 MySQL 5.5 版本开始就被当做默认存储引擎了。

然后我们来看看server层中这些组件的具体作用:

  • 连接器

    • 连接器主要和身份认证和权限相关的功能相关,就好比一个级别很高的门卫一样。
    • 主要负责用户登录数据库,进行用户的身份认证,包括校验账户密码,权限等操作,如果用户账户密码已通过,连接器会到权限表中查询该用户的所有权限,之后在这个连接里的权限逻辑判断都是会依赖此时读取到的权限数据,也就是说,后续只要这个连接不断开,即使管理员修改了该用户的权限,该用户也是不受影响的
  • 查询缓存(MySQL 8.0 版本后移除)

    • 查询缓存主要用来缓存我们所执行的 SELECT 语句以及该语句的结果集。连接建立后,执行查询语句的时候,会先查询缓存,MySQL 会先校验这个 SQL 是否执行过,以 Key-Value 的形式缓存在内存中,Key 是查询预计,Value 是结果集。如果缓存 key 被命中,就会直接返回给客户端,如果没有命中,就会执行后续的操作,完成后也会把结果缓存起来,方便下一次调用。当然在真正执行缓存查询的时候还是会校验用户的权限,是否有该表的查询条件。
    • MySQL 查询不建议使用缓存,因为查询缓存失效在实际业务场景中可能会非常频繁,假如你对一个表更新的话,这个表上的所有的查询缓存都会被清空。对于不经常更新的数据来说,使用缓存还是可以的。所以,一般在大多数情况下我们都是不推荐去使用查询缓存的。MySQL 8.0 版本后删除了缓存的功能,官方也是认为该功能在实际的应用场景比较少,所以干脆直接删掉了
  • 分析器

    • MySQL 没有命中缓存,那么就会进入分析器,分析器主要是用来分析 SQL 语句是来干嘛的,分析器也会分为几步:
      • 第一步,词法分析,一条 SQL 语句有多个字符串组成,首先要提取关键字,比如 select,提出查询的表,提出字段名,提出查询条件等等。做完这些操作后,就会进入第二步。
      • 第二步,语法分析,主要就是判断你输入的 SQL 是否正确,是否符合 MySQL 的语法。
    • 完成这 2 步之后,MySQL 就准备开始执行了,但是如何执行,怎么执行是最好的结果呢?这个时候就需要优化器上场了。
  • 优化器

    • 优化器的作用就是它认为的最优的执行方案去执行(有时候可能也不是最优,这篇文章涉及对这部分知识的深入讲解),比如多个索引的时候该如何选择索引,多表查询的时候如何选择关联顺序等。
    • 可以说,经过了优化器之后可以说这个语句具体该如何执行就已经定下来。
  • 执行器

    • 当选择了执行方案后,MySQL 就准备开始执行了,首先执行前会校验该用户有没有权限,如果没有权限,就会返回错误信息,如果有权限,就会去调用引擎的接口,返回接口执行的结果。

语句分析

查询语句

说了以上这么多,那么究竟一条 SQL 语句是如何执行的呢?其实我们的 SQL 可以分为两种,一种是查询,一种是更新(增加,修改,删除)。我们先分析下查询语句,语句如下:

select * from tb_student  A where A.age='18' and A.name=' 张三 ';

结合上面的说明,我们分析下这个语句的执行流程:

  • 先检查该语句是否有权限,如果没有权限,直接返回错误信息,如果有权限,在 MySQL8.0 版本以前,会先查询缓存,以这条 SQL 语句为 key 在内存中查询是否有结果,如果有直接缓存,如果没有,执行下一步。

  • 通过分析器进行词法分析,提取 SQL 语句的关键元素,比如提取上面这个语句是查询 select,提取需要查询的表名为 tb_student,需要查询所有的列,查询条件是这个表的 id=‘1’。然后判断这个 SQL 语句是否有语法错误,比如关键词是否正确等等,如果检查没问题就执行下一步。

  • 接下来就是优化器进行确定执行方案,上面的 SQL 语句,可以有两种执行方案:

    • 先查询学生表中姓名为“张三”的学生,然后判断是否年龄是 18。
    • 先找出学生中年龄 18 岁的学生,然后再查询姓名为“张三”的学生。
  • 那么优化器根据自己的优化算法进行选择执行效率最好的一个方案(优化器认为,有时候不一定最好)。那么确认了执行计划后就准备开始执行了。

  • 进行权限校验,如果没有权限就会返回错误信息,如果有权限就会调用数据库引擎接口,返回引擎的执行结果

更新语句

以上就是一条查询 SQL 的执行流程,那么接下来我们看看一条更新语句如何执行的呢?SQL 语句如下:

update tb_student A set A.age='19' where A.name=' 张三 ';

我们来给张三修改下年龄。其实这条语句也基本上会沿着上一个查询的流程走,只不过执行更新的时候肯定要记录日志啦,这就会引入日志模块了,MySQL 自带的日志模块是 binlog(归档日志) ,所有的存储引擎都可以使用,我们常用的 InnoDB 引擎还自带了一个日志模块 redo log(重做日志),我们就以 InnoDB 模式下来探讨这个语句的执行流程。流程如下:

  • 先查询到张三这一条数据,如果有缓存,也是会用到缓存。
  • 然后拿到查询的语句,把 age 改为 19,然后调用引擎 API 接口,写入这一行数据,InnoDB 引擎把数据保存在内存中,同时记录 redo log,此时 redo log 进入 prepare 状态,然后告诉执行器,执行完成了,随时可以提交。
  • 执行器收到通知后记录 binlog,然后调用引擎接口,提交 redo log 为提交状态。
  • 更新完成。

这里为什么要用两个日志模块,用一个日志模块不行吗?

这是因为最开始 MySQL 并没有 InnoDB 引擎(InnoDB 引擎是其他公司以插件形式插入 MySQL 的),MySQL 自带的引擎是 MyISAM,但是我们知道 redo log 是 InnoDB 引擎特有的,其他存储引擎都没有,这就导致会没有 crash-safe 的能力(crash-safe 的能力即使数据库发生异常重启,之前提交的记录都不会丢失),binlog 日志只能用来归档。

并不是说只用一个日志模块不可以,只是 InnoDB 引擎就是通过 redo log 来支持事务的。那么,又会有同学问,我用两个日志模块,但是不要这么复杂行不行,为什么 redo log 要引入 prepare 预提交状态?这里我们用反证法来说明下为什么要这么做?

  • 先写 redo log 直接提交,然后写 binlog,假设写完 redo log 后,机器挂了,binlog 日志没有被写入,那么机器重启后,这台机器会通过 redo log 恢复数据,但是这个时候 binlog 并没有记录该数据,后续进行机器备份的时候,就会丢失这一条数据,同时主从同步也会丢失这一条数据。
  • 先写 binlog,然后写 redo log,假设写完了 binlog,机器异常重启了,由于没有 redo log,本机是无法恢复这一条记录的,但是 binlog 又有记录,那么和上面同样的道理,就会产生数据不一致的情况。

如果采用 redo log 两阶段提交的方式就不一样了,写完 binlog 后,然后再提交 redo log 就会防止出现上述的问题,从而保证了数据的一致性。那么问题来了,有没有一个极端的情况呢?假设 redo log 处于预提交状态,binlog 也已经写完了,这个时候发生了异常重启会怎么样呢? 这个就要依赖于 MySQL 的处理机制了,MySQL 的处理过程如下:

  • 判断 redo log 是否完整,如果判断是完整的,就立即提交。
  • 如果 redo log 只是预提交但不是 commit 状态,这个时候就会去判断 binlog 是否完整,如果完整就提交 redo log, 不完整就回滚事务。

这样就解决了数据一致性的问题。

总结

我们总结一下:

  • MySQL 主要分为 Server 层和引擎层,Server 层主要包括连接器、查询缓存、分析器、优化器、执行器,同时还有一个日志模块(binlog),这个日志模块所有执行引擎都可以共用,redolog 只有 InnoDB 有。
  • 引擎层是插件式的,目前主要包括,MyISAM,InnoDB,Memory 等。
  • 查询语句的执行流程如下:权限校验(如果命中缓存)--->查询缓存--->分析器--->优化器--->权限校验--->执行器--->引擎
  • 更新语句执行流程如下:分析器---->权限校验---->执行器--->引擎---redo log(prepare 状态)--->binlog--->redo log(commit 状态)

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

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

相关文章

Move Dev Meetup杭州线下交流会圆满结束

北京时间6月17日下午2点到6点,由MoveFuns DAO 、MoveBit、ComingChat、杭州时戳微蓝信息咨询有限公司和WEB3CN联合举办的Move开发者线下交流会圆满结束。本次交流会吸引了110余名Move开发者报名,其中超过60位参会者成功来到现场参与了线下交流。 第一位分…

Python在不同领域中的应用

Python 是一种功能强大且易于使用的编程语言,因此在各个领域都有广泛的应用。以下是 Python 在不同领域中的应用: 数据科学:Python 是数据科学家和机器学习专家的首选工具之一。它有成熟的数据分析库和工具包,如 Pandas、NumPy、S…

逻辑回归模型的简介及python代码实现

文章目录 1 逻辑回归简介1.1 回归步骤1.2 逻辑回归与多重线性回归 2 逻辑回归模型算法原理2.1 逻辑回归模型的数学原理2.2 逻辑回归模型的代码实现2.3 逻辑回归模型的深入理解2.4 多分类逻辑回归模型演示 总结 1 逻辑回归简介 逻辑回归是分类当中极为常用的手段,它…

(六)关于Linux中服务器磁盘爆满问题的几个解决方案

文章目录 一、现象二、现象产生的原因三、问题的定位过程1.检查业务文件存放位置是否合理2.检查服务器系统盘空间是否分配过小3.对服务器磁盘占用情况进行分析4.若以上方案都解决不了内存占用过高问题,则考虑是否是服务器中存在其他容器产生了一些文件,比…

【使用Hystrix实现服务容错和熔断】—— 每天一点小知识

💧 使用 H y s t r i x 实现服务容错和熔断 \color{#FF1493}{使用Hystrix实现服务容错和熔断} 使用Hystrix实现服务容错和熔断💧 🌷 仰望天空,妳我亦是行人.✨ 🦄 个人主页——微风撞见云的博客&#x1f390…

进程、线程、协程?go中的协程原理详解 - 协程是什么?为什么要有协程?

1. 为什么要有协程? 我们使用工厂来表示计算机,而内存空间就相当于工厂的地皮,那么我们可以认为进程就是工厂中的厂房,它占据了工厂的地皮。(进程是分配资源的最小单位) 线程是什么呢?我们继续…

电商运营个人简历范文

电商运营个人简历篇1 个人信息 某某x 性 别: 男 婚姻状况: 已婚 出生年月: 1981年1月 民 族: 汉族 身 高: 175cm 最高学历: 大专 体 重: 70公斤 计算机能力: 高级程序员 技术职称&am…

MySQL的IF(exp1, exp2, exp3)、IFNULL(exp1, exp2)、ISNULL(exp)函数的用法

本章主要是讲解一下mysql的常用方法if()和ifnull()的使用 1、ISNULL(exp) 该函数的作用是判断表达式exp是否为null,如果是null,则返回1,否则返回0 案例代码:以上两条语句的查询结果为分别为1和0 select ISNULL(null) from dual…

管理类联考——逻辑——技巧篇——形式逻辑——考官出题套路

文章目录 考官出题套路一:代入逻辑推命题真假1. 考官出题套路特征:2. 核心考点: 考官出题套路二:判断逻辑真假1. 考点概述:2. 快速秒杀选项技巧: 考官出题套路三:推矛盾和“两难推理”1. 考点概…

一句话木马(绝对入门,实战环境安装+测试)主要是记录我的第一次一句话木马过程,复现40分钟左右。

首先介绍一下,搭建在本地的靶场,可以做渗透和注入的测试,真是好东西。 安装教程我推荐一篇博客,真的写的很好,我全程坐下来非常流畅非常流畅,csdn少见的高质量博客 DVWA下载安装_PisaYu的博客-CSDN博客 膜…

MFC第五天 Unicode软件开发 MFC框架构成与封装类原理

文章目录 Unicode软件开发以Unicode为字符集的记事本软件开发 MFC框架构成与封装类原理示例代码如下: Unicode软件开发 Unicode软件开发时需要遵循以下规则:使用中可尽量使用自适应版本。 Unicode软件开发: a)微软的软件工程现在默认使用Uni…

【MYSQL篇】mysql中相关锁和MVCC详解

文章目录 前言MVCC1、第一个事务2、第二个事务3、第三个事务4、第四个事务5、第五个事务 InnoDB 常见的几种锁机制共享锁排它锁意向锁记录锁间隙锁临键锁 小结 前言 数据库的锁是在多线程高并发的情况下用来保证数据稳定性和一致性的一种机制。MySQL 根据底层存储引擎的不同&a…

OpenGL

需要继承的两个类 #include <QOpenGLWidget> #include <QOpenGLFunctions_3_3_Core> class OpenGLWidget : public QOpenGLWidget,public QOpenGLFunctions_3_3_Core { Q_OBJECT public: explicit OpenGLWidget(QWidget *parent nullptr); virtual vo…

如何看待调查称半数年轻人存款不足10万?

文章目录 一、目前的存款在哪一个区间&#xff1f;你觉得存款难吗&#xff1f;2.1 自己的状态2.2 对理财的看法和态度 二、谈谈我为存款做出过哪些努力&#xff1f;三、除了个人因素外&#xff0c;有哪些因素影响到了年轻人的存款能力和存款意愿&#xff1f;四、要攒够多少存款…

【数据库原理与实践】CS系的实验期末考题(20222023)

2022&#xff1a; 学校管理数据库涉及四个关联表结构&#xff1a; 学生表 Student(Sno,Sname,Sdate,Ssex) &#xff0c;其中Sno学生编号&#xff0c;Sname学生姓名&#xff0c;Sdate出生年月&#xff0c;Ssex学生性别 。 课程表 Course(Cno,Cname,Tno) &#xff0c;其中Cno课…

(写自己语言的练手级应用)JSON(JavaScript Object Notation) 产生式(BNF)

写自己的开发语言时&#xff0c;很多人都会拿JSON当第一个练习对象 开源net json FJSON 解析工具https://dbrwe.blog.csdn.net/article/details/107611540?spm1001.2014.3001.5502 <json> :: <object> | <array> <object> :: "{" [ <me…

【OJ比赛日历】快周末了,不来一场比赛吗? #06.23-06.29 #13场

CompHub[1] 实时聚合多平台的数据类(Kaggle、天池…)和OJ类(Leetcode、牛客…&#xff09;比赛。本账号会推送最新的比赛消息&#xff0c;欢迎关注&#xff01; 以下信息仅供参考&#xff0c;以比赛官网为准 目录 2023-06-23&#xff08;周五&#xff09; #5场比赛2023-06-24…

k8s中如何修改pod中mysql的连接数

(方法一) 临时更改设置最大连接数据&#xff08;建议先临时修改&#xff0c;项目没有问题之后再进行永久修改&#xff09; 使用Navicat连接上数据库&#xff0c;点击连接名——点击新建查询—— 查看最大连接数 show variables like ‘’%max_connections%‘’; 查看当前用户使…

vue中注册组件的两种方式(全局注册 局部注册)

vue 是一个完全支持组件化开发的框架&#xff0c; 组件之间可以进行相互的引用。vue 中组件的引用原则&#xff1a;先注册后使用。 1. 组件的注册 组件之间可以进行相互的引用&#xff0c;例如&#xff1a; 注册组件的的方式&#xff1a;分为“全局注册”和“局部注册”两种…