学习总结录 学习总结录
首页
归档
分类
标签
  • Java基础
  • Java集合
  • MySQL
  • Redis
  • JVM
  • 多线程
  • 计算机网络
  • 操作系统
  • Spring
  • Kafka
  • Elasticsearch
  • Python
  • 面试专题
  • 案例实践
  • 工具使用
  • 项目搭建
  • 服务治理
  • ORM框架
  • 分布式组件
  • MiniSpring
  • 设计模式
  • 算法思想
  • 编码规范
友链
关于
GitHub (opens new window)
首页
归档
分类
标签
  • Java基础
  • Java集合
  • MySQL
  • Redis
  • JVM
  • 多线程
  • 计算机网络
  • 操作系统
  • Spring
  • Kafka
  • Elasticsearch
  • Python
  • 面试专题
  • 案例实践
  • 工具使用
  • 项目搭建
  • 服务治理
  • ORM框架
  • 分布式组件
  • MiniSpring
  • 设计模式
  • 算法思想
  • 编码规范
友链
关于
GitHub (opens new window)
  • Java基础

  • Java集合

  • MySQL

    • MySQL深入01-查询语句
    • MySQL深入02-更新语句
      • 更新语句执行流程
      • redo log
      • bin log
      • 两阶段提交
      • bin log和redo log的区别
      • 参考
    • MySQL深入03-事务隔离
    • MySQL深入04-深入浅出索引
    • MySQL深入05-全局锁、表锁、行锁
    • MySQL深入06-事务隔离再探
    • MySQL深入07-普通索引和唯一索引
    • MySQL深入08-为什么会选错索引
    • MySQL深入09-字符串字段加索引
    • MySQL深入10-脏页刷新
    • MySQL深入11-数据库表空间回收
    • MySQL深入12-count()
    • MySQL深入13-order by
    • MySQL深入14-正确显示随机消息
    • MySQL深入15-索引失效案例分析
    • MySQL深入16-查询一行数据执行慢
    • MySQL深入17-幻读
    • MySQL深入18-改一行语句锁问题
    • MySQL深入19-暂时提高数据库性能方案
    • MySQL深入20-这么保证数据不丢
    • MySQL深入21-主备一致的保证
    • MySQL深入22-高可用性的保证
    • MySQL深入23-备库延迟好几个小时
    • MySQL深入24-主库出问题,从库这么办
    • MySQL深入25-读写分离的过期读问题
    • MySQL深入26-判断数据库是否出问题
    • MySQL深入27-误删数据的处理方案
    • MySQL深入28-kill不掉的语句
    • MySQL深入29-查询对内存的影响
    • MySQL深入30-join深入
    • MySQL深入31-join语句优化
    • MySQL深入32-临时表深入
    • MySQL深入33-内部临时表何时使用
    • MySQL深入34-InnoDB和Memory
    • MySQL深入35-自增主键为什么不连续
    • MySQL深入36-insert语句的锁
    • MySQL深入37-如何快速复制一张表
    • MySQL深入38-grant和flush privileges
    • MySQL深入39-分区表
    • MySQL深入40-自增id用完如何处理
  • Redis

  • JVM

  • 多线程

  • 计算机网络

  • Spring

  • Kafka

  • Elasticsearch

  • Python

  • 面试专题

  • 知识库
  • MySQL
旭日
2023-03-26
目录

MySQL深入02-更新语句

# 更新语句执行流程

一条查询语句是经过了连接器、分析器、优化器、执行器等功能模块,最后到存储引擎执行数据的存取操作。那么对于一条更新语句到底经历了那些阶段呢?

在上一节中,我们有留意到,对于已经查询过的语句,MySQL会从查询缓存中去找到对应的key,然后返回对应key的value,而这个过程一旦发生MySQL的更新,这个查询缓存就会失效。更新语句就会把对应表的查询缓存失效,这是在查询缓存会执行的。

接下来,分析器会通过词法和语法解析知道这是一条更新语句。优化器决定要使用 ID 这个索引。然后,执行器负责具体执行,找到这一行,然后更新。

除此之外,还会涉及到两个重要的日志模块:

  • 重做日志(redo log)
  • 归档日志 (bin log)

# redo log

首先我们来了解一下WAL(Write-Ahead Logging):

数据库中一种高效的日志 (opens new window)算法,对于非内存数据库 (opens new window)而言,磁盘I/O操作 (opens new window)是数据库效率的一大瓶颈。在相同的数据量下,采用WAL日志的数据库系统 (opens new window)在事务 (opens new window)提交时,磁盘写操作只有传统的回滚 (opens new window)日志的一半左右,大大提高了数据库磁盘I/O操作的效率,从而提高了数据库的性能。

这里我们试想MySQL如果每一次更新操作都是去写进磁盘,那么整个IO成本和资源是非常高的,所以就会采用先写日志,再写磁盘的方式。

比如系统比较繁忙,但此时来了一条更新操作,这时候MySQL的InnoDB 引擎就会先把记录写到redo log,并更新内存,相当于这时候我只是拿了一张草稿纸记录了一下,但是并没有实际写入我的答题卷中。而当系统空闲的时候,InnoDB 引擎就会将这个更新操作记录更新到磁盘中,相当于我要把草稿纸的内容填写到答题卷上了。

这时候还会出现一个问题,当我们考试的时候,如果我草稿纸满了,这么办?

这时候我们就会把草稿纸已经核对的部分填写到答题卷上,然后把已经核对部分用橡皮擦掉,腾出空间方便后续的记录。

同样MySQL也是类似的原理,只是清除部分已经录入磁盘的更新记录,为后续新的更新记录腾出空间。

image-20220620165412405

write pos就是当前记录的位置,一边写一边后移,checkpoint就是当前要擦除的位置,也是往后推移并且循环的,擦除记录前要把记录更新到数据文件。

write pos 和 checkpoint 之间的是“粉板”上还空着的部分,可以用来记录新的操作。如果 write pos 追上 checkpoint,表示“粉板”满了,这时候不能再执行新的更新,得停下来先擦掉一些记录,把 checkpoint 推进一下。

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

这就好比,你的答题卷突然摧毁了,但是你的草稿纸还保留着做题记录。

image-20220510110257596

# bin log

上面所讲的redo log是InnoDB 引擎所特有的功能,而我们知道MySQL主要分为两大部分:Server层和存储引擎,而bin log就是Server层所特有的日志(归档日志)。

两日志的区别如下:

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

更新流程如下:

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

image-20220510143938394

# 两阶段提交

我们可以看到在更新操作的最后三步,执行了"两阶段提交",这是为了redo log和bin log两份日志之间的逻辑一致。现在我们来假设两个案例:

1、先写redo log,再写bin log

如果我们的更新操作,已经写入了redo log,但还没有写入bin log,此刻我们的数据已经发生变化了,如果此刻系统崩溃了。由于redo log相当于一个备忘录的存在,那么重启系统之后,MySQL是可以通过redo log这个备忘录去恢复数据。

但是由于没写入bin log,相当于bin log里面没有记录这条更新操作。以后如果需要使用bin log来恢复临时库,但是由于bin log没有这条记录,所以会导致我们使用bin log恢复之后,数据库这条记录还是更新操作之前的数值。

2、先写bin log,再写redo log

如果在 binlog 写完之后 系统崩溃,由于redo log里面没有记录这条操作,所以系统恢复之后,数据库这条数据的数值还是操作之前的数值。但是由于bin log记录了,之后如果我们使用bin log去恢复临时库,临时库恢复出来这条数据的数值则是操作之后的数值。

# bin log和redo log的区别

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

image-20230327094138680

# 参考

MySQL 实战 45 讲-极客时间 (opens new window)

#MySQL
上次更新: 2024/06/29, 15:13:44
MySQL深入01-查询语句
MySQL深入03-事务隔离

← MySQL深入01-查询语句 MySQL深入03-事务隔离→

最近更新
01
基础概念
10-31
02
Pytorch
10-30
03
Numpy
10-30
更多文章>
Theme by Vdoing | Copyright © 2021-2024 旭日 | 蜀ICP备2021000788号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式