MySQL 更新语句执行流程

124 阅读2分钟

有如下表

mysql> create table T(ID int primary key, c int);

需要执行如下更新语句

mysql> update T set c=c+1 where ID=2;

MySQL内部是如何执行的?

首先,看一下MySQL逻辑结构

跟查询语句不一样的是,在更新执行语句时,会把表对应的查询缓存都清空,在高版本的MySQL中,查询缓存默认被取消掉了

接下来,分析器会通过词法和语法解析知道这是一条更新语句。优化器决定要使用 ID 这个索引。然后,执行器负责具体执行,找到这一行,然后更新。、

在SQL更新语句执行过程中,还涉及到两个重要日志文件,redo Log和binLog。

redoLog和binLog

redoLog是InnoDB存储引擎特有的。当有一条记录需要更新时,InnoDB存储引擎会把记录先存储到redoLog中,并更新内存。同时,InnoDB存储引擎会在适当的时候把记录存储到磁盘中。这个时候一般是在比较空闲的时候来做。 、 redoLog是环形数组结构,主要有两个位置,check point,write pos。write pos是当前写的位置,checkpoint 是当前要擦除的位置,也是往后推移并且循环的,擦除记录前要把记录更新到数据文件。

redoLog能够保证在数据库出现崩溃或者其他异常情况下,保证数据不丢失。这是如何实现的呢?

这个需要redoLog和binLog两个配合来实现。redoLog写的时候分为两个阶段,第一个阶段是prepare阶段,第二个阶段是commit阶段。binLog的写只有一个阶段。

以update T set c=c+1 where id = 1; ID=2;为例子分析更新语句的执行过程。

1、根据id主键查询对应的记录,如果记录已经在内存中,则直接返回。如果没有,则从磁盘读取到内存中。

2、对内存中的数据,执行加1操作。

3、写入redoLog,此时为prepare阶段。

4、写入binLog

5、commit bigLog

两阶段递交

为什么必须有“两阶段提交”呢?这是为了让两份日志之间的逻辑一致。

由于 redo log 和 binlog 是两个独立的逻辑,如果不用两阶段提交,要么就是先写完 redo log 再写 binlog,或者采用反过来的顺序。我们看看这两种方式会有什么问题。

先写 redo log 后写 binlog

redo Log写完,系统崩溃,binLog还未写,会造成主从复制时数据不一致。从库会少sql语句。

先写binLog 后写redo Log

bin Log写完后,系统崩溃,此时redo Log还没有写。会造成binLog中写入无效数据 、