1

前言

当我们执行一条 sql 更新语句时,你有没有想过,它的在 MySQL 系统内部是如何去执行的?当我们购买 MySQL 服务器时,你有没有考虑过为什么 MySQL 服务器内存大,硬盘为 SSD 的话比较好?(当然,这是废话,什么服务器,内存大,硬盘为 SSD 都好,但 MySQL 服务器要求还是比业务代码服务器要求高些)
以下我们以表 Tupdate sql 为例进行分析(默认InnoDB引擎):

create table T(ID int primary key, c int);
update T set c=c+1 where ID=2; 

执行逻辑

一个 update 语句的执行逻辑为:
1、通过连接器连接 MySQL Server层
2、连接器阶段初步分析为 update 交给分析器处理;
3、分析器详细分析 update 语句,进行词法、语法、语义检查,生成解析树以供优化器使用,并在交给优化器之前进行权限检查(precheck)
4、优化器将解析树优化,生成最优执行计划,交给执行器执行;
5、执行器在执行 sql 时会再次检查权限,并调用引擎层提供的数据接口,对数据进行更新处理。

更新语句和查询语句不同之处在于,当我们执行更新时,对数据的敏感性是比较强的,我们需要保证数据更新正确,且万一的万一,MySQL 崩溃了,我们也能恢复数据,所以更新操作涉及到记录日志,这里的日志就是我们熟知的 MySQL Server层binlog日志InnoDB引擎层的 redolog日志

所以,update时,在上面执行逻辑中的第5步执行器执行阶段的处理过程为:
1、执行器取ID=2的数据;
2、引擎判断数据页是否在内存中,没有则从磁盘读取到内存中,从内存中返回行数据;(内存大的服务器的好处)
3、执行器将该数据值加1,之后写入新行,通知引擎
4、引擎将新数据更新到内存中
5、引擎此时开始记录redolog,并将该记录置为prepare状态
6、执行器写binlog
7、引擎提交事务,并更新此行数据的redolog状态为commit
8、当MySQL空闲时,会将内存中的数据落盘。
流程图:【深色为执行器执行,浅色为引擎处理】
update.png
以上就是更新数据时,执行器和引擎做的一系列操作。

整个更新过程其实是AWL技术,即Write-Ahead Logging预写式日志。先写日志,再更新。

分析

我们可能会有疑问:为什么在binlog存在的情况下,我们还要额外引入redolog呢?

我们详解之前,先讨论下binlogredolog是什么。
binlogMySQL Server层提供的日志记录功能,所有引擎都能用,它是记录sql执行逻辑的,如给ID=2这一行的c字段+1,且binlog日志是追加记录的,当文件写到一定大小会新增一个新文件继续记录,属于全量日志。

redolog则是InnoDB独有的日志,其他引擎不可用,且redolog记录的是在某个数据页上做了什么修改,属于物理日志,只有InnoDB才能用,且是固定大小,循环记录的。

现在我们来分析为什么binlogredolog并存的问题。
binlogredolog是通过事件ID去关联的。
简单来说,binlogredolog并存可以保证数据一致性,以及意外宕机时的数据恢复问题。也就是MySQLcrash-safe

  • 如果我们只记录binlog,那么我们只有操作记录,如果日志记录了,但是数据没更新到表里,当我们使用binlog恢复表时,会出现数据不一致。
  • 单独记录redolog是不行的,因为redolog是循环记录的,会抹去旧的日志,不像binlog一样,是全量的。(资料显示,现在已经有在做redolog全量存储的第三方团队了,基于数据页的数据恢复一致性更强,且不用记两份日志)
  • 如果先记录binlog再记录redolog的话,若写完binlog数据库崩了,此时没有记录redolog,当重启数据库时,因为redolog没记录,所以此事务操作无效,库中值不会改变,但是binlog中又有此条记录,导致使用binlog恢复数据时,会更新值,导致数据不一致。
  • 如果先记录redolog再记录binlog的话,若写完redolog数据库崩了,此时没有记录binlog,重启数据库,虽然能通过redolog正确恢复到之前的数据更新,但是因为binlog没记录,之后备份恢复时,还是会导致数据不一致。

最后

最后,举个简明的卖东西例子去概括下redologbinlog的记录过程:
一个完整的交易过程应该是:
1、账本记录卖一瓶可乐(redolog 处于 prepare
2、收钱放入抽屉(binlog
3、收完钱,在账本该记录上打对勾,代表抵账(redolog 置为 commit
若收钱过程被打断,则整理交易时,发现只是记账了却没收钱,则删除该账本记录(回滚)
若收了钱,有事情耽误了抵账,那么之后闲下来对账的时候,将账本该记录打勾即可(即commit


风雨之间
20 声望2 粉丝