02日志系统一条SQL更新语句是如何执行的?

写在前面

以下内容基于InnoDB存储引擎分析。

01基础架构:一条SQL查询语句是如何执行的 一文中我们分析了mysql的基础架构,了解了一个sql语句执行的简单流程,为了方便回忆,再来贴下架构图:

在这里插入图片描述

如果是我们执行了如下的更新语句mysql> update T set c=c+1 where ID=2;,也是经过上述的各种组件处理吗?答案是肯定的,但是因为是更新数据,肯定涉及到新数据的写入,所以具体的流程细节上又会有所不同,主要的不同之处就在于执行器这里,接下来我们就一起来看下,具体参考1:更新语句在执行器做了什么?

1:更新语句在执行器做了什么?

当更新语句比如update T set c=c+1 where ID=2;执行到执行器,执行器因为需要完成数据更新任务,所以首先需要调用存储引擎的获取数据接口获取到ID=2的数据,然后执行c=c+1,然后调用存储引擎的更新接口将ID=2的c数据更新为c+1。当存储引擎返回更新完毕后,执行器还有一个非常重要的工作要做,即备份数据,这个备份数据的方式就是写binlog,具体我们在3:两阶段提交来分析。在前面我们提到执行器会调用存储引擎接口读取数据以及调用更新数据接口更新数据,这个过程我们通过2:更新语句在存储引擎做了什么?

2:更新语句在存储引擎做了什么?

当存储引擎收到了执行器获取数据的接口调用后,会先检测数据对应的数据页是否在内存中,如果是在,返回,否则读取磁盘获取对应的数据页,然后返回。数据在执行器经过了计算得到了需要更新的结果,又执行到存储引擎更新数据,此时存储引擎在将数据更新对应的内存后(注意此时还没有落盘)后,会将更新信息写到redo log中,然后返回成功消息给执行器。关于redo log,具体我们在3:两阶段提交来分析。

3:两阶段提交

在前面的分享中,我们提到了两种日志,redo log,binlog,其中redo log是InnoDB存储引擎所特有的,让MySQL具备了crash safe的能力,binlog提供了数据备份和恢复的能力。当MySQL异常重启之后恢复数据需要使用到redo log,当需要恢复数据时需要使用到binlog,因此二者在逻辑上需要保持一致性,而二者的写入又不是同步的,binlog由Server层执行器负责写入,redo log由存储引擎层的InnoDB存储引擎负责写入的,为了能够实现二者在逻辑上的一致性,就有了两阶段提交,以sql语句update T set c=c+1 where ID=2;为例,这个过程如下:

1:执行器通过存储引擎接口获取ID=2的数据,数据页内存有则直接取内存中的,否则从磁盘获取,将行数据返回给执行器。
2:执行器执行数学运算,假设ID为2的c原始值为N,则经过数学运算后变为N+1,得到一行新的数据。然后调用存储引擎接口写入这行新数据。
3:存储引擎拿到这行新数据后,首先将数据更新到内存中,同时也会将更新写到redo log中,并将redo log中的记录标记为prepare状态,然后返回给执行器自己已准备完毕的消息,随时可以commit提交事务。
4:执行器生成binglog,并把binlog写入到磁盘中。
5:执行器最后调用存储引擎的事务提交接口,存储引擎会将3中redo log从prepare状态修改为commit状态。

这个过程详细的如下图:

在这里插入图片描述

关于redo log和binlog我们继续从接下来的内容一起看下。

3.1:redo log

InnoDB并非mysql自带的存储引擎,其自带的存储引擎是MyISAM,而MyISAM并不具备crash safe的能力。于是MySQL就以插件的形式引入了三方公司开发的存储引擎InnoDB,InnoDB存储引擎通过redo log提供了crash safe的能力,redo log设计的结构是一个环形的循环写入存储结构,该环形存储结构由若干个文件组成,比如3个文件组成的结构,如下图:

在这里插入图片描述

其中的红色区域代表已写入数据区域还未同步到磁盘的数据修改,蓝色区域代表空闲区域,write pos代表下一个可以写入redo log的位置,checkpoint代表需要同步到磁盘的开始位置。假设突然数据库宕机,因为事务已经提交了,修改就算是同步到磁盘也肯定在redo log中,假设就是红色区域的这些修改内容,再次启动数据库后只需要将红色区域的修改同步到磁盘中就可以了,这样就实现了crash safe的能力。

3.1.1:多知道一点之change buffer

还有一个和redo log类似的概念change buffer(使用InnoDB buffer pool内存空间),二者都会记录对于page的更新操作,但其作用是缓存page更新的结果,提高数据更新的速度,然后在以下的三种情况会merge到磁盘ibd文件中:

1:需要查询对应的页数据
2:后台线程定时merge
3:数据库正常shutdown

其实从概念上看很容易区分redo log和change buffer二者的区别,但是对于二者都会记录对于page的更新操作这点,也比较容易让人产生疑惑,接下来我们通过一个例子来具体看下,假设执行sql语句mysql> insert into t(id,k) values(id1,k1),(id2,k2);,并且假设(id1,k1)要写入的page在缓存中,则写入后结构可能如下图:

在这里插入图片描述

图中的1,是将(id1,k1)直接写到对应的内存中的页Page1中,图中的2,是记录添加(id2,k2)的操作到change buffer中,然后同步到对应的磁盘idbdata中,3,4,是在redo log中记录添加(id1,k1),(id2,k2)的页操作,实现crash safe。所以,可以看到change buffer只是记录了page不在内存中时对应的页操作(添加(id1,k1)就不需要记录,因为页在内存中,直接操作页即可),而redo log则是为了实现crash safe,记录了所有的页操作。

redo log避免了写入更新后数据时的随机IO,change buffer避免了读取要更新的数据的随机IO。

3.2:binlog

binlog是在server层提供的日志形式,mysql自带,日志的归档,可用于日志恢复,数据备份,增加从库时初始化数据等,binglog主要提供了两种格式的日志存储,一种是statement,另一种是row,其中statement格式存储的就是sql语句本身,row格式存储的两条语句更新前和更新后的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值