MySQL(二)一条update更新语句的执行流程

一、图概览

下面先用一个张图概览一下更新语句的执行流程,进一步来讲的话一条更新语句可以作为一个事务,也就是MySQL处理事务的流程。
在这里插入图片描述

再用文字详细叙述之前,我们先来解决几个问题,这也是我在画这张图中遇到的问题。因为基础知识比较薄弱,边画这张图边解决问题差不多花了两天多的时间,所以还请各位看官看完觉得有收获的话记得点个赞。

解决几个问题

1.undo log、redo log、binlog都存了些什么东西?

  • Undo log:逻辑日志,存储执行sql语句之前的数据和该sql语句相反的操作语句。比如执行一条delete操作undo会记录一条与之对应的insert语句,反之亦然;执行一条update操作,undo log会记录一条与update操作相反的记录
  • Redo log:物理日志,记录哪个数据页(包括data page和undo page)做了什么修改
  • binlog:逻辑日志,记录语句的原始逻辑,如给id为2的age字段加1

2.undo log存储在哪?
undo log的实现由两个组成,一个是Buffer Pool中的undo page页,一个是磁盘中的Undo logs文件。
但是不管是在Buffer Pool还是磁盘上,undo log和普通的数据一样。在Buffer Pool中undo log存在于undopage,undopage和datapage一样,遵循bufferpool的淘汰机制。

二、文字版详细流程

文字版在图的基础上做了进一步的扩展,比如要给Buffer Pool加锁、涉及doublewrite buffer等这些都会在后面讲到。先看下具体流程吧,分为MySQL Server处理事务、InnoDB处理事务、提交事务三个阶段。

1.MySQL Server处理事务

1.首先客户端通过tcp/ip发送一条sql语句到server层的SQL interface
2.SQL interface接到该请求后,验证权限是否匹配
3.验证通过以后,分析器会对该语句分析,包括词法分析、语法分析、语义分析等
4.接下来是优化器生成相应的执行计划,选择最优的执行计划
5.之后会是执行器根据执行计划执行这条语句。在这一步会去open table。如果该table上有MDL,则等待。如果没有,则加在该表上加短暂的MDL(S)(如果opened_table太大,表明open_table_cache太小。需要不停的去打开frm文件)

2.InnoDB处理事务

6.进入到引擎层,首先会去innodb_buffer_pool里的data dictionary(元数据信息)得到表信息。并且通过元数据信息去lock_info(一种内存数据结构)里查出是否会有相关的锁信息,并把这条update语句需要的锁信息写入到lock info里

7.这条线程得到锁之后,首先该sql语句修改前的数据载入到undo page里。这条线程会先去查看buffer pool中查看是否有该语句的data page(数据页),如果有data page则直接将data page中的数据载入到buffer pool里的undo page里。如果没有则需要去磁盘取数据载入到undo page里。并将物理undo page页面修改的信息记录到redo log buffer中

8.之后该线程在会buffer pool的data page做update操作,并把操作的物理data page页面修改信息记录到redo log buffer中。由于update这个事务会涉及到多个页面的修改,所以redo log buffer里会记录多个页面修改信息。因为group commit的原因,这次事务所产生的redo log buffer可能会跟随其他页面一同flush并且sync到磁盘上。

9.开始记录binlog_cache。该条线程同时将修改的信息按照event的格式,记录到binlog_cache里,binlog_cache存在于线程栈中。(这里注意binlog_cache_size是transaction级别的,不是session级别的参数。一旦提交之后,dump线程(主从同步master开的线程)会从binlog_cache里把event主动发送给slave的I/O线程)

10.接下来该条线程开始修改sql涉及到的二级索引页,如果修改了将信息暂时写入到change buffer page,等到下次有其他sql需要读取该二级索引时,再去与二级索引做merge(该操作也是利用了随机I/O变为顺序I/O,读写性能会更高些)

11.此时update语句已经完成了Buffer Pool中data page的修改,undo page修改(undo 日志),redo log日志缓存记录以及该条线程binlog_cache缓存,需要commit事务或者rollback事务。

3.提交事务

12.先讨论commit事务的情况。由于存储引擎与server层之间采用的是内部XA(保证两个事务的一致性,这里主要保证redo log和binlog的原子性),所以提交分为prepare阶段与commit阶段。并且采用双1(指的就是innodb_flush_log_at_trx_commit和sync_binlog都设置成 1。也就是说,一个事务完整提交前,需要等待两次刷盘,一次是redo log(prepare 阶段),一次是binlog。)

13.perpare阶段将事务xid写入,将binlog_cache里的进行flush以及sync操作(大事务的话这步非常耗时),写入到binlog文件中。

14.commit阶段由于之前该事务产生的redo log已经sync到磁盘了。所以这步只是在redo log里标记commit。

15.当binlog和redo log都已经落盘之后,如果触发了刷新脏页的操作,先把该脏页复制到doublewrite buffer里,把doublewrite buffer里,把doublewrite buffer里的刷新到共享表空间,然后才是通过page cleaner线程把脏页写入到磁盘中。

  • 11
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序猿成长轨迹

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值