mysql执行一条sql语句的完整过程,sql语句在mysql中的执行过程

本文深入解析MySQL中SQL语句的执行流程,包括客户端、服务器层与innoDB引擎层的详细过程。重点阐述了undo日志、redo日志与binlog日志的作用与区别,揭示了MySQL如何通过这些机制保障数据的一致性和事务的正确性。

1. SQL语句在mysql的执行过程

一条更新语句完整流程图如下所示:

在这里插入图片描述

步骤:

一:客户端层

id为1的name字段原来的值是zhuge

  • ①:mysql的客户端执行sql
 update t set name = 'zhuge666' where id = 1;

        

二:mysql服务器层

  • ②: 进入mysql服务器,由连接器验证账号密码等身份信息,验证通过去查mysql缓存,如果有,直接返回。没有进入分析器。
  • ③:进入mysql的分析器,分析sql语句是否符合mysql规范。
  • ④:进入sql优化器,mysql底层优化sql,比如调换索引列等。
  • ⑤:进入执行器,执行sql。
            

三:innoDB引擎层

mysql服务层后边连接了很多引擎层,如MyIsaminnoDB等,这里只分析innoDB引擎。

以一个update语句为例,看一下inndb是如何执行,并实现底层事务的!

  • ⑥:加载磁盘上id为1的整页数据到 buff pool缓存池中,此时buff pool中的name值为zhuge,为什么加载整页,因为磁盘上存储数据都是整页整页存的。这里要注意:mysql加载数据是整页整页加载的!!
  • ⑦:把buff pool中的 旧值 zhuge 写入undo日志版本链,方便事务提交失败后回滚,回滚时直接从undo日志版本链中取值即可。
  • ⑧:在buff pool中把新的值 zhuge666 赋给 name,注意此时只有buff pool中的name属性做了更新,磁盘上的文件还是原来的旧值 zhuge
  • ⑨:执行器把更新的操作先写入内存中的Redo Log buffer(Redo日志缓冲区)
  • ⑩:把Redo日志缓冲区分批次顺序写入inndb独有的redo磁盘日志文件中,此时准备提交事务,事务状态为prepare阶段
  • ⑪:把更新操作写入binlog日志,内容与redo日志差不多,属于mysql服务层,所有引擎层都有这一步操作。此时还是准备提交事务中,还没提交 。
  • ⑫:写一个commit标记到redo日志中去,redolog修改事务状态为commit ,该标记为了保证事务提交后,redo日志和binlog日志数据一致。此时才标志着提交事务完成
            
  1. 问题一:binlog为什么要给redo日志中写一个commit标记?
    • binlog主要用于恢复数据,提交事务时,要给redo日志中写一个commit标记可以保证binlog日志中的数据与redo日志中的数据保持一致性
  2. 问题二:磁盘文件的数据什么时候更新?
    • 不确定,有一个后台io线程从Buffer pool缓存池中随机以页为单位写入磁盘。
  3. 问题三:为什么Mysql不能直接更新磁盘上的数据,而是设置这么一套复杂的机制来执行SQL?
    • ①:内存操作,异步刷盘:如果每个请求都要来更新磁盘,数据库性能将特别差。利用buff poll缓存池在内存中操作数据,定时写入磁盘,大大提高了数据库性能。
    • ②:redo日志顺序写入磁盘redo日志虽然也使用磁盘存储,但相对与直接随机读写磁盘来说,redo日志是顺序写磁盘日志文件的。顺序写入的速度远高于随机写入,同时redo日志还能保证各种异常情况下的数据一致性。 正是通过这套机制,才能让我们的MySQL数据库在较高配置的机器上每秒可以抗下几干的读写请求。
              

2. redolog、binlog是如何协作,来保证mysql崩溃后数据的一致性的?

        
当一个事务提交时,redologbinlog的协作分为两个阶段:

  • 阶段一:Prepare(准备阶段)
    • InnoDB将事务的变更写入Redo Log Buffer,并fsync同步写入到磁盘的Redo Log文件中(可能攒一批事务再写)。
    • 此时Redo Log中记录的事务状态为prepare(注意:此时事务还未真正提交),不完全算是真实有效的数据,除非有binlog提供的commit标记
    • 这个阶段完成后,即使发生崩溃,事务的修改已经持久化在Redo Log中。
  • 阶段2:Commit(提交阶段)​
    • MySQL Server层将事务的变更写入Binlog文件(调用fsync同步写,确保持久化)
    • 一旦Binlog写入完成,InnoDB引擎将Redo Log中对应事务的状态标记为commit

        
mysql在事务提交过程中崩溃,重启后会进入崩溃恢复流程。崩溃恢复的决策逻辑如下:

mysql恢复时先扫描Redo Log和Binlog,根据Redo Log中已写入操作的事务状态,又分为如下几种情况

  • ​​情况1:Redo Log状态为 commit
    • 说明事务已经安全提交(Binlog肯定已写入),是一个正常已完成的事务,需要恢复。Redo Log中又记录了数据的物理修改(在哪个数据页做了什么修改),直接重做事务修改的数据页即可。
  • ​​情况2:Redo Log状态为prepare​​(需要结合Binlog判断)
    • ​​如果 Binlog 中存在该事务的完整记录:说明Binlog已成功写入(事务在阶段2:Commit 提交阶段崩溃),但InnoDB未标记commit。那这个时候redolog就需要变更事务状态为commit,然后重做事务修改的数据页。因为 Binlog 完整意味着从库已经 或者 将要收到这个事务,为了主从同步的一致性,redolog必须变更状态,并同步修改主库的磁盘数据。
    • 如果Binlog中不存在该事务记录或者不完整:说明事务在阶段1后、写Binlog前崩溃,此时需要使用UndoLog回滚事务。因为Binlog未写入,从库不可能有这个事务,主库必须回滚以保持主从一致!

思考:为什么这种协作模式能够保证mysql数据的一致性呢?

核心逻辑:​​Binlog的完整性决定了事务的命运​​

  • 如果Binlog写成功(事务完整记录),即使InnoDB未提交(状态为prepare),恢复后也会强行提交。
  • 如果Binlog未写或写一半,即使Redo Log已持久化(prepare状态),也要回滚事务。

这就确保了:

  • ​​主库数据安全​​:已提交的事务不会因为崩溃丢失(Redo Log保障)
  • ​​主从严格一致​​:主库提交的事务,从库一定能收到(Binlog保障);主库回滚的事务,从库一定不会收到。

        

3. undolog、redolog、binlog的区别?

三种日志都写入磁盘!不过undo日志和redo日志是innoDB存储特有的,binlog日志是所有存储引擎都有的!

  • undo日志:主要用于mvcc机制的实现,还有事务回滚也可直接从undo日志中取到原始值
  • redo日志:主要用于防止mysql宕机时,buff pool中的数据还未来得及写入磁盘,导致数据丢失。使用redo日志可在mysql宕机后再启动时,把数据恢复到buff pool中。第二点就是等待binlog日志发送commit标记后才提交事务,保证与binlog日志文件数据一致!
  • binlog日志:主要用于数据库数据误删恢复,主从复制
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值