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

一、mysql更新

我们先从一个表的更新开始说起,下面是建表的语句,这个表有一个主键ID和一个整型字段c;

create table T(ID int primary kry,c int);
insert into T(c) values(1);

如果要将ID=2这一行的值加1,SQL语句就会这么写

update T set c=2 where ID=0;

mysql语句的更新流程有两个重要的日志模块:redo log(重做日志)和binlog(归档日志)。如果接触MySQL,那么这两个词是肯定绕不过的

二、重要的日志模块

1、redo log

redo log是InnoDB内置的日志模块,他的大小是固定的,不支持持久化存储,比如配置4个一组文件,每个文件的大小是1GB,那么就可以记录4G的操作,写到末尾就又从头开始循环,如下图所展示的。

write pos是当前记录的位置,一边写一边往后移动,写到第三号文件末尾的时候就回到0号文件开头。checkpoint是当前要擦除的位置,也是往后移动并且循环,在擦除记录前要把记录更新到硬盘数据文件上。
write pos和checkpoint之间是空白部分,用来记录新的操作。如果write pos追上checkpoint,表示这4G的文件以及写满了,这时候就不能执行更新操作,需要checkpoint将数据推一下,留出来一定的空间位置。

有了 redo log,InnoDB 就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力称为crash-safe。

2、binlog

binlog主要是将server层的日志进行归档,那么为什么会有两分日志呢?因为最开始MySQL里面并没有InnoDB引擎,MySQL自带的引擎是MyISAM,但是MyISAM没有crash-safe的能力,binlog日志只能用来归档。而InnoDB是以插件的形式引入MySQL的,既然只依靠binlog是没有crash-safe的能力的,所以InnoDB使用了另外一套日志系统也就是redo log来实现crash-safe能力。

3、binlog和redo log的不同点

1.redo log是InnoDB引擎特有的;binlog是MySQL的Server层实现的,所有引擎都可以使用。
2.redo log是物理日志,只记录了在某个数据页上做了什么修改;binlog是逻辑日志,记录的是这个语句的原始逻辑,比如给”ID=0这一行的c字段设置为2“;
3.redo log是循环写的,空间有固定大小;binlog是可以追加写入的。追加写是指binlog文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。

4、update语句的执行流程

1.执行器先找到ID=0这一行。如果ID=0这一行在内存中在内存中,就直接返回给执行器;否则需要从磁盘读入内存在返回给执行器。
2.执行器拿到行数据后,对字段的值进行修改得到一行新数据,在调用引擎接口写入这行数据。
3.引擎将这行数据更新到内存中,同时将更新的操作记录到redo log中,此时redo log处于prepare(准备状态)。然后告知执行器执行完成了,随时可以提交事务。
4.执行器生成这个操作的binlog,并把binlog写入磁盘。
5.执行器调用引擎的提交事务接口,引擎把刚刚写入的redo log进行提交,更新完成。

原文地址:https://www.cnblogs.com/charon2/p/11755413.html