Update语句执行流程
大黄 Lv4

Update语句执行流程 流程.jpg

Update语句执行流程 参考.png

先刷redo log盘,然后再删除redo log日志。(redo log刷盘操作是幂等的)


两阶段提交思想

redo log

刷脏页

我们的一条SQL语句,正常执行时速度特别快,但是有的时候不知道为什么,速度特别慢。

那么可能是因为MySQL在刷脏页导致的(flush)

首先先介绍下什么是脏页

  • 脏页:内存数据页跟磁盘数据页内容不一致,我们就会称呼这个内存页为脏页
  • 干净页:内存数据写入到磁盘后,内存和磁盘上的数据页的内容就一致了。

刷脏页的几种情况

  • redo log写满了,此时系统会停止所有更新操作,把checkpoint向前推进,redo log留出空间后才能继续写(redo log是个环形,会涉及到删除原有的内容)
  • 需要记录的数据太多,内存页不够,需要淘汰一些数据页,空出内存给别的数据页使用。淘汰的是脏页的话,就要先将脏页写到磁盘中
  • MySQL认为系统空闲的时候,会刷脏页
  • MySQL正常关闭的时候,会刷脏页

MVCC(MySQL隔离性的保证)

相关概念

视图:InnoDB在实现MVCC时用到的一致性读视图(consistent read view,用于支持RC和RR隔离级别的实现),此处要与查询语句的虚拟表视图(view)区分

多版本和row trx_id

为了保证可重复度,事务在启动时需要对数据库拍一个快照。但是对整个数据库的数据备份一份,无疑是一个很耗性能的工作。那么InnoDB是如何保证可重复度的呢?

基于版本号与undolog

InnoDB每个事务都有一个唯一的事务ID(transaction id),在事务启动时向InnoDB的事务系统申请的,根据申请顺序严格递增的

同时每行数据都是有多个版本的,每次事务更新的时候,都会生成一个新的数据版本,并把transaction id复制给这个数据版本的事务ID,记为 row trx_id。同时也会保存旧的数据版本

Update语句执行流程 MVCC多版本

U1,U2,U3就是对应的undo log,而V1,V2,V3并不是真是存在的。是根据当前版本和undo log计算出来的

同时,在查询数据的时候,就会以当前事务启动时的版本号为准,对记录进行查找,一直找到当前事务之前的版本号的数据为准

undolog何时删除?在系统中没有比这个回滚日志更早的read-view时,就会删除undolog


**2023/10/10更新**

MySQL运行过程中Crash的该如何恢复

redo log里记录了数据页的修改以及change buffer新写入的信息
如果掉电,持久化的change buffer数据已经purge,不用恢复。主要分析没有持久化的数据
情况又分为以下几种:
(1)change buffer写入,redo log虽然做了fsync但未commit,binlog未fsync到磁盘,这部分数据丢失
(2)change buffer写入,redo log写入但没有commit,binlog以及fsync到磁盘,先从binlog恢复redo log,再从redo log恢复change buffer
(3)change buffer写入,redo log和binlog都已经fsync.那么直接从redo log里恢复。

关于ChangeBuffer对更新时候的帮助

1
2
-- a为普通索引,b为普通索引
update table_a set a = 1 where b = 2 and version = 0;

首先先明确下ChangeBuffer的作用
当需要更新一个数据页时,如果数据页在内存中就直接更新,而如果这个数据页还没有在内存中的话,在不影响数据一致性的前提下,InnoDB 会将这些更新操作缓存在 change buffer 中,这样就不需要从磁盘中读入这个数据页了。在下次查询需要访问这个数据页的时候,将数据页读入内存,然后执行 change buffer 中与这个页有关的操作。
由上面的这句话我们可以得出两个结论

  • ChangeBuffer适用的场景: 非唯一索引变更
  • ChangeBuffer的优点: 减少对索引页的随机读, 提高修改数据的效率

那么我们结合前面的执行流程图和ChangeBuffer,分析下刚刚上面的那个sql, 它在执行的时候分别做了哪些事情?

  • 查找索引b, 获取对应的主键id列表
  • 回表, 加载对应数据所在的数据页到内存中
  • 修改内存中的数据
  • 对索引a的修改,记录到change buffer中
  • redo log prepare状态
  • binlog
  • redo log commit状态
  • 返回成功

关于binlog是否完整如何判断

  • statement 格式的 binlog,最后会有 COMMIT;
  • row 格式的 binlog,最后会有一个 XID event。

为什么prepare阶段的redo log加上完整的binlog事务就可以提交

加入binlog写完之后,MySQL发生崩溃,此时binlog已经写入,后面从库包括我们恢复这个奔溃的MySQL都会使用到这个binlog,所以此时奔溃的主库也要提交事务

关于写 redolog

此时MySQL会用到redolog buffer。在插入数据的过程中,生成的日志会先写入到redolog buffer中,等待commit语句执行时redolog buffer才会刷盘

  • Post title:Update语句执行流程
  • Post author:大黄
  • Create time:2021-12-26 13:47:21
  • Post link:https://huangbangjing.cn/2021/12/26/Update语句执行流程/
  • Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.