一条update SQL语句是如何执行的

一条更新语句的执行过程和查询语句类似,更新的流程涉及两个日志:redo log(重做日志)和binlog(归档日志)。比如我们要将ID(主键)=2这一行的值加(c:字段)1,SQL语句如下:

update T set c=c+1 where ID=2;
  • redo log

  重做日志是InnoDB引擎特有的,是物理日志,记录在“某个数据页上做了什么修改“。大小是固定,可以进行配置大小。假如我们配置一组4个文件,图中write pos是当前记录的位置,往后推移并且循环;checkpoint是当前要擦除的位置,移动规律和前者一样。两者之间的位置可以记录新的操作

 

  

如果write pos 追上checkpoint,就移动checkpoint擦除一些记录。所以即使数据可以发生异常重启,InnoDB也可以保证之前提交的记录不会丢,这就是MySQL的crash_safe能力。

  • binlog

  归档日志是MySQL的server层的实现的,所有引擎都可以使用。binlog记录的是sql语句的原始逻辑,比如根剧’id’字段查询所有的信息;相比redo log的循环写入,binlog是追加写的,binlog文件写到一定大小后会切换到下一个,不会覆盖以前的日志。

Binlog有两种模式,statement 格式的话是记sql语句, row格式会记录行的内容,记两条,更新前和更新后都有。

上述语句在InnoDB中的执行流程如下:深色代表在执行器中执行的,浅色是在存储引擎中。

最后写入redolog分为了prepare和commit两步,用来保证两个日志写入的一致性,这就是“两阶段提交”。比如我们执行“update T set status = 1“时:

  • 如果写入redolog成功,但写binlog失败,重启恢复时,数据库发现没有commit,那么事务本身回滚;备份恢复时没有binlog,数据库里的status值不变。
  • 如果在commit失败,重启恢复时redolog和binlog一致,重新commit;备份恢复时有binlog,直接恢复。

总的来说binlog记录了对数据库所有的逻辑操作,可以通过binlog来备份出一份完全相同的库;因为redolog是InnoDB引擎特有的,如果使用其他引擎,那么就要依赖binlog来记录操作。

思考一个问题:定期全量备份的周期“取决于系统重要性,有的是一天一备,有的是一周一备”。那么在什么场景下,一天一备会比一周一备更有优势呢?或者说,它影响了这个数据库系统的哪个指标?

一天一备,那么如果需要恢复数据的话,只要保证当天的binlog完整即可;一周一备的话就要保证一周的binlog完整;同时频繁全量备份需要更多存储空间,如何选择取决于业务的重要性,对应的指标是RTO(目标恢复时间)。

 — 《MySQL实战45讲》笔记二

Tags: