• 02|一条MySQL更新语句是如何执行的


    02|一条MySQL更新语句是如何执行的

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

    其实一条更新语句的执行操作和查询语句的执行操作基本相同->一条SQL查询语句是如何查询的?,唯一不同的是一条更新语句在执行过程中需要涉及到两个日志操作(redo log、binlog)。步骤如下:

    1. 连接器:建立一个链接

    2. 分析器:词法优化、语法优化

    3. 优化器:给出该条SQL语句执行方案

    4. 执行器:如下

    • 执行器先找引擎取 ID=2 这一行。ID 是主键,引擎直接用树搜索找到这一行。如果 ID=2 这一行所在的数据页本来就在内存中,就直接返回给执行器;否则,需要先从磁盘读入内存,然后再返回。
    • 执行器拿到引擎给的行数据,把这个值加上 1,比如原来是 N,现在就是 N+1,得到新的一行数据,再调用引擎接口写入这行新数据。
    • 引擎将这行新数据更新到内存中,同时将这个更新操作记录到 redo log 里面,此时 redo log 处于 prepare 状态。然后告知执行器执行完成了,随时可以提交事务。
    • 执行器生成这个操作的 binlog,并把 binlog 写入磁盘。
    • 执行器调用引擎的提交事务接口,引擎把刚刚写入的 redo log 改成提交(commit)状态,更新完成。

    img

    redo log

    首先我们思考一个问题,那就是当我们每执行一条更新操作,MySQL是否都会将更新的数据立即写入磁盘?答案是:否

    因为如果每一次的更新操作都需要写进磁盘,然后磁盘也要找到对应的那条记录,然后再更新,整个过程 IO 成本、查找成本都很高。因此为了解决这个问题,MySQL设计者采用了WAL技术。具体来说就是当有一条记录需要更新时,InnoDB引擎就会先把这条记录写入到redo log中,并且更新内存,此时更新就算完成了。同时,InnoDB引擎会在合适的时候将记录写到磁盘中,而这个操作往往是在系统比较空闲的时候去做。

    但是可能会存在一些问题,要是系统一直不空闲怎么办?redo log日志的容量是多大?

    redo log日志容量是固定的,比如可以配置为一组 4 个文件,每个文件的大小是 1GB,那么这块日志总共就可以记录 4GB 的操作。当日志写不下了,那就会将最开始的那块日志更新到数据文件,同时对这块日志进行擦除,进而腾出空间继续写入。

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

    binlog

    MySQL 整体来看,其实就有两块:一块是 Server 层,它主要做的是 MySQL 功能层面的事情;还有一块是引擎层,负责存储相关的具体事宜。上面我们聊到的 redo log (重做日志)是 InnoDB 引擎特有的日志,而 Server 层也有自己的日志,称为 binlog(归档日志)。

    这两种日志有以下三点不同。

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

    为什么需要两阶段提交呢?这是为了让两份日志之间的逻辑一致。

    • 先写 redo log 后写 binlog

    当写完redo log日志后,binlog 还没有写完的时候,MySQL 进程异常重启。这个时候我们仍然可以通过redo log日志将数据恢复,这样看起来并没有什么问题。但是我们可以想一下,当我们之后备份数据的时候,备份的是bin log日志,如果需要用这个 binlog 来恢复临时库的话,由于这个语句的 binlog 丢失,这个临时库就会少了这一次更新,数据就会与原值不一致。

    • 先写binlog后写redo log日志

    如果在 binlog 写完之后 crash,由于 redo log 还没写,崩溃恢复以后这个事务无效。但是 binlog 里面已经记录了该条修改日志。所以,在之后用 binlog 来恢复的时候就多了一个事务出来,与原库的数据不一致。

    小结
    • Bin log 用于记录了完整的逻辑记录,所有的逻辑记录在 bin log 里都能找到,所以在备份恢复时,是以 bin log 为基础,通过其记录的完整逻辑操作,备份出一个和原库完整的数据。

    • redo log用于崩溃恢复,当MySQL崩溃重启以后,能够通过redo log将数据正确恢复到崩溃前的值。

  • 相关阅读:
    秩序的美——队列的基础实现
    BYOL for Audio: Exploring Pre-trainedGeneral-purpose Audio Representations笔记
    2、python的lambda表达式
    [iOS]static、extern、const关键字比较
    Android sqlcipher 对于加密的Sqlite库在Mac上进行解密的正确姿势
    QT 插件化图像算法软件架构
    Proxy应用场景
    JMeter 调试取样器(Debug Sampler)简介
    Jenkins学习笔记3
    基于C++的RSA公钥加密算法实验
  • 原文地址:https://blog.csdn.net/qq_23587709/article/details/126670531