MySQL中一条更新语句的执行过程

首先假设有这么一条SQL更新语句:

update users set name='xxx' where id = 10

这个语句是如何执行的呢?首先就是我们的客户端通过一个数据库连接将语句发送到MySQL上,然后经过SQL接口,解析器,优化器,执行器几个环节,解析SQL语句,生成执行计划,接着由执行器调用InnoDB存储引擎的接口去实际执行,然后返回结果给客户端。

在这里插入图片描述

1. 查询数据

更新语句的第一步就是查询到对应记录。所以首先就是要查询 “id=10” 的记录。InnoDB在查询的时候会先从缓冲池(Buffer Pool)中查找。Buffer Pool 的作用就是就是缓存数据,这样在查询的时候,如果数据在缓存中,则可以直接从缓存中查询,避免了查磁盘。例如上面的更新语句首先要将磁盘中 “id=10” 的数据加载到Buffer Pool中来。

bp
此外要注意,如果是执行更新语句的时候,需要对这一条数据加锁更新。

2. 写入 undo 日志文件

undo 日志是用来支持事务处理中数据回滚的,它是存储引擎层(innodb)生成的日志,undo log 记录的是逻辑操作日志,比如对某一行数据进行了INSERT语句操作,那么 undo log就记录一条与之相反的DELETE操作。
。假设 “id=10” 这行数据的name原来是 “zhangsan”,现在我们要更新为 “lisi”,那么首先需要把原始值 “zhangsan” 和 “id=10” 这些信息写入到undo日志文件中去。
undo

3. 更新 Buffer Pool 中的数据

把需要更新的那条记录加载到缓冲池之后并对其加锁,然后写入原始值到 undo log,这样就保证了可以更新数据并且原始数据不会丢失。接着就可以对缓冲池中的数据进行更新了,也就是把内存里的 “id=10” 这条记录的 name 修改为 “lisi”。但是这样修改之后这条记录其实是脏数据,因为内存中的数据和磁盘上的数据此时是不一致的。如下图:
update

4. 写入 redo log buffer 内存缓冲区

redo log 也是存储引擎层(innodb)生成的日志,redo log是一种物理日志,记录的是“在某个数据页上做了什么修改”。它的作用主要就是为了避免宕机是发生数据丢失,例如按照上图所示,内存里的数据已经更新完成,但是还没有刷入磁盘,如果此时发生宕机,那么内存中修改过的数据就会丢失。这个时候就需要先把修改后的数据记录在redo log buffer中。但是这个时候我们又会有疑问了 redo log buffer 还是在内存中,如果宕机了怎么办。和undo日志不一样的是,redo日志是先写入内存,再刷入磁盘,并且有3种刷盘策略。

5. 写入 redo log 磁盘文件

其实redo log主要是为了在事务提交时,所有的操作都能同时完成,并且可以防止MySQL服务端宕机导致事务提交的修改丢失。所以在提交事务的时候需要将redo log buffer中的redo日志刷入磁盘文件。刷盘策略是通过 innodb_flush_log_at_trx_commit 来配置的,包括几个选项:

  • innodb_flush_log_at_trx_commit=0:提交事务时,不会立即把redo log buffer中的数据刷入磁盘,会在适当的时候统一刷盘。但是这样的话可能在MySQL宕机时内存中的redo log全部丢失。
  • innodb_flush_log_at_trx_commit=1:一般使用这个策略。提交事务时,立即把redo log buffer中的数据刷入磁盘,只要事务提交成功,那么redo log就必然在磁盘里了。可以保证每次事务提交的修改不丢失。如下图:

redolog
这样的话,由于更新后的数据已经刷入redo日志文件,即使系统宕机了,内存中的数据丢失了,还可以通过redo日志文件来恢复之前修改的数据。

  • innodb_flush_log_at_trx_commit=2:提交事务时,先把redo log buffer中的日志写入对应的os cache缓存里去,而不是直接刷入磁盘文件。可能系统在1秒之后才会把os cache里的数据刷入磁盘文件。
6. 提交事务的同时,写入binlog

bin log 是 MySQL 数据库层面上生成的日志,主要用于 point in time 恢复和主从复制。和undolog 一样,bin log也是一种逻辑日志。在提交事务的时候,不仅会吧redo log刷入磁盘,也会把这次更新对应的binlog刷入磁盘。

binlog
上图中的1,2,3,4几个步骤是在执行更新语句时发生的操作,而5,6两个步骤则是在提交事务的阶段发生的操作

binlog 的刷盘策略可以通过sync_binlog参数控制,包括以下几种策略:

  • sync_binlog=0:提交事务时先写入os cache,然后等待系统刷入磁盘文件。
  • sync_binlog=1:强制在提交事务时,直接把binlog写入磁盘文件。
7. 基于redo log和binlog完成事务提交

当binlog写入磁盘(或os cache)之后,就这就会完成最终的事务提交操作。此时会把本次更新对应的binlog文件名和本次的binlog记录对应的offset写入到redo log日志文件里去,同时在redo log中写入一个commit标记。这样才算完成了事务的提交,如果没有commit标记就代表此次事务提交失败。如下图:
commit

8. 后台IO线程将内存中更新过的脏数据刷入磁盘

假设现在事务提交了,当前的状态是undo log保存了更新前的数据,redo log和binlog也保存了此次更新的数据,buffer pool中也保存了当前最新的数据,但是磁盘上的数据文件还未修改,内存和磁盘上的数据是不一致的。所以MySQL有一个后台IO线程,会在之后的某个随机时间把buffer pool中的脏数据写入磁盘数据文件,这样内存和磁盘上的数据就一致了。如下图:
ioflush
这样磁盘上的原始数据也就更新完成,并且保证了事务的成功执行以及避免宕机出现数据丢失的情况。


THE END.

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值