高性能Mysql——一条SQL语句在Mysql中是如何执行的?

2023-11-06


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

在分析之前我会先带着你看看 MySQL 的基础架构,知道了 MySQL 由那些组件组成已经这些组件的作用是什么,可以帮助我们理解和解决这些问题。

MySQL 基本架构概览

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

  • Server 层:主要包括连接器、查询缓存、分析器、优化器、执行器等,所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图,函数等,还有一个通用的日志模块 binglog 日志模块。
  • 存储引擎: 主要负责数据的存储和读取,采用可以替换的插件式架构,支持 InnoDB、MyISAM、Memory 等多个存储引擎,其中 InnoDB 引擎有自有的日志模块 redolog 模块。现在最常用的存储引擎是 InnoDB,它从 MySQL 5.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 可以分为两种,一种是查询,一种是更新(增加,更新,删除)。

  • 更新语句执行流程如下:
    (1)分析器
    (2)权限校验
    (3)执行器调用引擎
    (4)引擎执行
    (5)写入redo log(prepare 状态)
    (6)写入binlog
    (7)写入redo log(commit状态)

我们可以详细的说明下这两个执行过程。

查询语句

查询语句,语句如下:

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

  1. 连接器
    连接器是半双工的通信,在mysql与客户端连接后,验证请求用户的权限:首先检查账户和密码是否正确,如果用户的账户和密码验证通过,会在mysql自带的权限表中查询当前用户的权限。
  2. 查询缓存
    在 MySQL8.0 版本以前,会查询缓存,缓存以key和value的哈希表形式存储,key是具体的sql语句,value是结果的集合。如果无法命中缓存,就继续走到分析器的的一步,如果命中缓存就直接返回给客户端 。
    不过需要注意的是在 MySQL8.0 版本以后,缓存被官方删除掉了。之所以删除掉,是因为如果在一个写多读少的环境中查询缓存的失效非常频繁,所以一般是建议在客户端上做缓存。
  3. 分析器
    通过分析器对sql语句做语法分析和词法分析,生成语法树。在这个阶段会解析sql语句的关键词和非关键词进行提取,并且对于整个语句的有效性做判断。如果分析到语法错误,会直接给客户端抛出异常:ERROR:You have an error in your SQL syntax。这个阶段也会做一些校验:比如校验当前数据库是否存在sql语句的表和字段,没有则会报错unknown column in field list。
  4. 优化器
    主要是进行sql语句的优化,比如多个索引的时候该如何选择索引,多表查询的时候如何选择关联顺序等。
  5. 执行器
    在执行器的阶段会调用存储引擎的API

更新语句

我们就以 InnoDB 模式下来探讨这个语句的执行流程。流程如下:

  1. 连接器
  2. 清空缓存
    不同的是,写会把缓存清空,防止出现数据不一致。
  3. 解析器
    也是会生成一个语法树,并且解析器会知道这是一个更新语句。
  4. 优化器
    优化器决定是否用到索引,要使用哪个索引。
  5. 执行器
    执行器负责具体执行,根据索引或者全表扫描查找到这行数据,然后修改更新数据。InnoDB 引擎把更新完的数据保存在内存中,同时记录 redo log,此时 redo log 进入 准备(prepare) 状态。
    之后执行器调用引擎APi来提交事务,并且将提交 redo log 更新为提交(commit)状态。

SQL执行过程的日志问题

这里肯定有同学会问,为什么要用两个日志模块,用一个日志模块不行吗?

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

为什么 redo log 要引入 prepare 预提交状态?这里我们用反证法来说明下为什么要这么做?

  • 先写 redo log 直接提交,然后写 binlog,假设写完 redo log 后,机器挂了,binlog 日志没有被写入,那么机器重启后,这台机器会通过 redo log 恢复数据,但是这个时候 bingog 并没有记录该数据,后续进行机器备份的时候,就会丢失这一条数据,同时主从同步也会丢失这一条数据。
  • 先写 binlog,然后写 redo log,假设写完了 binlog,机器异常重启了,由于没有 redo log,本机是无法恢复这一条记录的,但是 binlog 又有记录,那么和上面同样的道理,就会产生数据不一致的情况。
  • 如果采用 redo log 两阶段提交的方式就不一样了,写完 binglog 后,然后再提交 redo log 就会防止出现上述的问题,从而保证了数据的一致性。那么问题来了,有没有一个极端的情况呢?假设 redo log 处于预提交状态,binglog 也已经写完了,这个时候发生了异常重启会怎么样呢? 这个就要依赖于 MySQL 的处理机制了,MySQL 的处理过程如下:
  1. 判断 redo log 是否完整,如果判断是完整的,就立即提交。
  2. 如果 redo log 只是预提交但不是 commit 状态,这个时候就会去判断 binlog 是否完整,如果完整就提交 redo log, 不完整就回滚事务。

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

高性能Mysql——一条SQL语句在Mysql中是如何执行的? 的相关文章

  • java图片验证码在服务器上返回乱码问题

    本机上没有问题 部署在阿里云服务器上都几个月了都没有问题 上传过一次代码后突然验证码就显示为看不懂的符号了 然而代码对此并没有影响的 打印生成的验证码 String word vcu produceNumAndChar length LOG

随机推荐

  • ES集群节点宕机导致shard unassigned解决方案

    ES集群概况 1台master节点 4台data节点 9个shards 问题 一台data节点宕机 导致5个分片处于unassigned状态 集群状态变为red 无法自动rerouting 解决步骤 1 查看所有节点的日志信息 通过日志 我
  • 开源数据目录管理工具_Java开发中用到的数据库迁移工具(flyway)

    什么是数据库版本管理 任何web软件和应用程序都需要强大的数据库管理工具 因此开发者选择一款合适的数据库管理工具尤为重要 本文列出了几款好用的数据库管理工具 有些并非开源或免费 以供开发者们参考选择 做过开发的小伙伴们都知道 实现一个需求时
  • ***没有规则可以创建“XXX”需要的目标“XXX”问题的解决方案

    在第4季 上学期 专题2 U Boot新手入门中 1 在Linux中解压uboot tq2440 tar gz 2 tar xvzf uboot tq2440 tar gz 3 进入 uboot tq2440 4 make TQ2440 c
  • 软件加密系统Themida常见问题集锦—Themida是否支持命令行保护?

    Themida是先进的Windows软件保护系统 它被用于满足软件开发人员对于所开发应用程序安全保护的需求 使其远离被先进的逆向工程和软件破解的危险 通过下载Themida 我们集中在软件保护器所具有的主要弱点 从而提供了解决这些问题的完整
  • jdbc oracle多数据源,JdbcTemplate 配置多数据源

    有时候需要对接第三方厂商的数据库或者视图 我们不想让多数据源入侵我们现有的项目 那么可以试下JdbcTemplate 这里以Oracle视图为例 先确定下对方Oracle版本 然后引入对应版本的pom org springframework
  • SNKr:创造新的潮圈文化 将区块链与时尚潮流结合

    直播内容整理 关于SNKr SNKr以 Real Recognize Real 为核心愿景 是一个由区块链赋能的潮流文化生态社区项目 由SWELL公司发起 SNKr致力于连接潮流文化中的 真 玩家与 真 产品 通过loT和区块链技术帮助品牌
  • AcWing110. 防晒

    输入样例 3 2 3 10 2 5 1 5 6 2 4 1 输出样例 2 解析 按照右区间排序 优先满足小的 include
  • python读取图片的几种方式

    opencv的像素值在 0 1 0 1 show的时候转换到 0 255 import cv2 img cv2 imread imgfile cv2 imshow img win name img cv2 waitKey 0 无限期等待输入
  • 不要自称为程序员

    如果有我可以添加到每个工程教育的一门课程 它不涉及编译器或门或时间复杂度 这将是您工业101的现实 因为我们不教他们和许多不必要的痛苦和折磨这个结果 这后立志要为你作为一个年轻的工程师的职业生涯中的自我介绍 填写在您的教育差距 就如何在 现
  • TMPGEnc 4.0 XPress(小日本4)优化安装教程

    小日本4 TMPGEnc 4 0 XPress 是小日本2 54的升级版本 与小日本2 54之间本来还有一个3 0 版本 不过3 0 没有产生太大影响即升级到4 0 版本 尽管是小日本2 54的升级版本 但3 0 以后此软件便属于全新开发
  • VirtualBox安装OpenWRT虚拟机,及Kernel panic - not syncing: Attempted to kill init故障排除

    编译或下载镜像文件 openwrt x86 generic Generic combined ext4 img gz 解压 gunzip d openwrt x86 generic Generic combined ext4 img gz
  • c++构建正态分布的随机数

    最近编程的时候遇到一个问题 需要用c 来产生一个满足正态分布的的随机数 用c 产生一个均匀分布的随机数很容易 但是满足正态分布还是有点懵逼的 然后就在网上搜一些资料 发现有三种方法可以产生正态分布的随机数 但是看别人从理论上的推导 感觉还是
  • node——使用Nginx + Node.js部署你的网站

    Nginx是一个高性能的HTTP和反向代理服务器 反向代理就是通常所说的web服务器加速 它是一种通过在繁忙的web服务器和internet之间增加一个高速的web缓冲服务器来降低实际的web服务器的负载 Nginx由俄罗斯程序员利用C语言
  • python的动态加载的一个注意地方

    先描述一下我的问题背景 然后给出错误发现 最终给出解决办法 1 我有很多python文件 并且这些文件内容会按照一定周期被更新但是文件名字不变 并且每个文件内都有一个一样的class的名字 需要我去动态调用 我的调用方法是使用的python
  • Spring-03 Aop简介,实现原理,基于ProxyFactoryBean实现Aop,基于AspectJ开发的实现

    Spring 03 1 SpringAop简介 AOP的全称是Aspect Oriented Programming 即面向切面编程 也称面向方面编程 它是面向对象编程 OOP 的一种补充 目前已成为一种比较成熟的编程方式 aop 解决的问
  • C语言——白盒测试

    深入理解白盒测试的基本方法 运用基本路径测试法设计测试用例 1 掌握白盒测试技术中基本路径测试法的基本步骤 2 训练针对具体程序运用基本路径测试法设计测试用例的能力 测试代码 DEVcpp 源代码 点击此处可下载 include
  • Android 自动化触发GC

    问题 最近有个小需求 能通过自动化对app进行GC回收 对于app的处理无外乎主动调用System gc 或者使用adb命令直接进行GC回收 解决方法 方法一 在代码里的某个方法调用System gc 如我申明一个receiver 然后通过
  • linux:SecureCRT SSH连接报错 Key exchange failed. No compatible key exchange method

    问题 配置ssh后提示 Key exchange failed No compatible key exchange method The server supports these methods curve25519 sha256 cu
  • 数据分析36计(九):倾向得分匹配法(PSM)量化评估效果分析

    1 因果推断介绍 如今量化策略实施的效果评估变得越来越重要 数据驱动产品和运营 业务等各方的理念越来越受到重视 如今这方面流行的方法除了实验方法AB testing外 就是因果推断中的各种观察研究方法 统计相关性并不意味着因果关系 数据分析
  • 高性能Mysql——一条SQL语句在Mysql中是如何执行的?

    文章目录 MySQL 基本架构概览 Server层介绍 SQL执行过程 查询语句 更新语句 SQL执行过程的日志问题 本篇文章会分析下一个 sql 语句在 MySQL 中的执行流程 包括 sql 的查询在 MySQL 内部会怎么流转 sql