一条Update语句的执行过程是怎样的?

2023年 7月 14日 56.8k 0

前言

通过本文主要了解Sql执行流程,包括两个问题:

  • MySQL的一条Select语句是怎么运行的
  • MySQL的一条Update语句是怎么运行的
  • 先看第一个问题,这里做个简单描述 ,因为我们着重还是看Update

    MySQL执行一条Select语句是怎么运行的?

    这个问题大家在面试的时候大家都背过类似的题,而且网上也有很多答案,这里分享一个大致流程介绍,关于下图的介绍来自这里 执行一条 select 语句,期间发生了什么?。

    • 连接器:建立连接,管理连接、校验用户身份;
    • 查询缓存:查询语句如果命中查询缓存则直接返回,否则继续往下执行。MySQL 8.0 已删除该模块;
    • 解析 SQL,通过解析器对 SQL 查询语句进行词法分析、语法分析,然后构建语法树,方便后续模块读取表名、字段、语句类型;
    • 执行 SQL:执行 SQL 共有三个阶段:
    • 预处理阶段:检查表或字段是否存在;将 select * 中的 * 符号扩展为表上的所有列。
    • 优化阶段:基于查询成本的考虑, 选择查询成本最小的执行计划;
    • 执行阶段:根据执行计划执行 SQL 查询语句,从存储引擎读取记录,返回给客户端

    相对于Select,内容更多和更复杂的是Update语句的执行,接下来我们讲展开细讲,再看本文之前可以先看看之前的分享,这两篇文章对Double Write和Buffer Pool有做详细的介绍:

    MySQL的Double Write如何保证可靠性?

    InnoDB的Buffer Pool是如何管理数据页的?

    当然最好也了解下 redolog、undolog、binlog的相关知识点,这块知识我们会在后续继续分享!

    Update执行逻辑

    先把我画的图看完,图中步骤比较多,需要花点时间看,你想我画这个肯定花了更长时间,如果觉得还不错的话,谢谢点赞收藏下,不足的话大家指正下!

    执行流程图

    整个流程的架构很清晰:Client客户端、Server层、InnoDB引擎层、磁盘,这里就不对每个组件的具体功能和细节处理做更详细的解释了,文章主要是帮我们把流程理清楚!

    核心组成部分

    当然这里也涉及到几个核心:Buffer Pool、Double Write、Redo Log、Undo Log、BinLog、WAL

    Buffer Pool和Double Write可以参考我之前的文章,在开头就有分享原文链接,我们来看以下问题!

    Redo Log、Undo Log、BinLog分别存的什么内容,分别是做什么用的?

  • Redo Log 在引擎层实现,用来恢复数据的,保障已提交事务的持久化特性,记录的是物理级别的数据页(包括data page和undo page)做的修改
  • Undo Log 在引擎层实现的逻辑日志,用于数据回滚到之前状态,对于每个UPDATE语句,对应一条相反的UPDATE的undo log
  • BinLog 是Server实现的逻辑日志,用于复制和恢复数据,记录了所有的 DDL 和 DML 语句(除了数据查询语句select、show等)
  • WAL是什么,哪里用到了它?

    WAL全称为Write-Ahead Logging,预写日志系统。主要写undo log、redo log、binlog这些用到了。

    真正使用WAL的原因是:磁盘的写操作是随机IO,比较耗性能,所以如果把每一次的更新操作都先写入log中,那么就成了顺序写操作,实际更新操作由后台线程再根据log异步写入

    UndoLog会存储在哪些地方?

    我们从图中也可以清晰的知道UndoLog在两个地方:Buffer Pool中的undo page页,和磁盘中的表共享空间的Undo log

    详解执行流程

    看完执行流程图大家都有个大概印象了,我们分三个部分进行更具体的文字化描述,一起来看看吧!

    Client客户端:

  • 客户端通过tcp/ip发送一条sql语句到server层
  • Server层:

  • 接收客户端过来的请求,进行权限验证
  • 权限验证通过后,解析器会对SQL语句进行词法、语法分析等
  • 经过验证解析的SQL语句会在优化器生成选择最优执行计划
  • 然后执行器将会执行经过优化的SQL语句
  • Server层和存储引擎之间怎么通信的呢?

    到这里用户发送的一个SQL已经经过各种验证、分析、优化到了执行阶段,那么接下来就是执行器怎么和InnoDB存储引擎打交道了。

    对于Server层来说,它是不知道存储引擎的实现细节的,而是通过定义的API接口和存储引擎通信。可以理解为存储引擎是一个类,然后每个实例(InnoDB)都通过一个特殊的处理程序接口与MySQL服务器通信。

    InnoDB引擎层:

    现在已经到了引擎层了,存储引擎主要负责数据的存储和读取

  • 调用存储引擎接口后,会先从Buffer Pool获取数据页,如果没有就从磁盘中读入Buffer Pool,然后判断更新前后的记录是否一样
  • 开启事务,修改数据之前先记录undo log,写入Buffer Pool的undo page
  • 开始更新page data中的记录,被修改的数据页称为脏页,修改会被记录到内存中的 redo log buffer中,再刷盘到磁盘的redo log文件,此时事务是 perpare阶段
  • 这个时候更新就完成了,当时脏页不会立即写入磁盘,而是由后台线程完成,这里会用double write来保证脏页刷盘的可靠性
  • 还没结束呢,这时候可以通知Server层,可以正式提交数据了, 执行器记录binlog cache,事务提交时才会将该事务中的binglog刷新到磁盘中
  • 这个时候Update语句完成了Buffer Pool中数据页的修改、undo日志、redo log缓存记录,以及记录binlog cache缓存
  • commit阶段,这个阶段是将redo log中事务状态标记为commit
  • 此时binlog和redo log都已经写入磁盘,如果触发了刷新脏页的操作,先把脏页copy到double write buffer里,Double Write Buffer 的内存数据刷到磁盘中的共享表空间 ibdata,再刷到数据磁盘上数据文件 ibd
  • 流程完结
  • 什么是二阶段提交?

    二阶段提交,顾名思义,会包含 2 个阶段:

    prepare 阶段,协调器会询问所有执行器,是否可以提交事务

    commit 阶段,协调器会通知执行器进行提交操作

    update的执行阶段也用到了,比如:

    • prepare 阶段:将 redo log 对应的事务状态设置为 prepare,然后将 redo log 刷新到硬盘;
    • commit 阶段:将 binlog 刷新到磁盘,接着调用引擎的提交事务接口,将 redo log 状态设置为 commit(将事务设置为 commit 状态后,刷入到磁盘 redo log 文件)

    总结

    今天的分享就到这了,我们平时一条Update语句其实内部会经历很多流程,语句解析、日志WAL,Buffer Pool等。通过今天这篇文章的分享相信大家对流程已经很清晰了,后续将继续带来Redo Log、UndoLog等内容,敬请期待!

    👨👩 你好,朋友,希望本文对你有帮助~🌐
    欢迎点赞 👍、收藏 💙、关注 💡 三连支持一下~🎈
    我会继续输出更高质量文章进行分享~🙇💻

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论