前言
在数据库里面,我们说的 update
操作其实包括了更新、插入和删除。更新流程和查询流程有什么不同呢?今天我想把MySQL的更新过程拆解一下,借由这个过程,对MySQL有更深入的了解,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。
回顾一条查询语句的执行过程
首先,我们来回顾一条查询语句的执行过程,一条查询语句的执行过程一般是经过连接器、分析器、优化器、执行器等阶段后,最后到达存储引擎。执行流程图如下:
更新语句的执行过程
更新SQL语句的执行过程与查询的基本一致,经过连接器、分析器、优化器、执行器等阶段后再进行update,重点在于多了一点东西,那就是redo_log
、undo_log
和binlog
。更新语句的执行过程图如下:
执行流程如下:
- 客户端发送更新命令到MySQL服务器,执行语句前要先连接db–连接器的工作;
- 服务端先看下查询缓存,对于更新某张表的SQL,该表的所有查询缓存都失效;
- 接着来到解析器,进行语法分析,校验语法是否合规;
- 然后优化器进行SQL优化,比如怎么选择索引之类,生成执行计划;
- 执行引擎去存储引擎查询需要更新的数据,存储引擎判断当前缓冲池中是否存在需要更新的数据,存在就直接返回,否则去从磁盘加载数据。
- 存储引擎更新修改到内存中;
- 存储引擎记录redo日志,并将状态设置为prepare状态;
- 存储引擎通知执行器,修改完毕,可以进行事务提交;
- Server先写了个binlog;
- Server提交事务;
- 存储引擎将redo日志中和当前事务相关的记录状态设置为commit状态。
重要的日志模块——redo log
redo_log
又叫重做日志,是 InnoDB
引擎特有的日志,用来记录事务操作的变化,记录的是数据修改之后的值,不管事务提交是否成功,都会被记录下来,如果服务器出问题了,我们就从这个日志文件里面读取数据,恢复数据——保证数据的持久性与完整性。
重要的日志模块——binlog
之前你可能经常听DBA同事说,MySQL
可以恢复到半个月内任意一秒的状态,你是不是也会好奇这是怎样做到的呢?其实主要是应用到的binlog
日志。
binlog日志我们又称归档日志,在server
端生成的以二进制形式存储,以事件的形式记录了所有的 DDL
和 DML
语句(因为它记录的是操作而不是数据值,属于逻辑日志),可以用来做主从复制和数据恢复。
两阶段提交
由于redo_log
和 binlog
是两个独立的逻辑,在不保证两个逻辑都能执行成功的情况下,那么数据库的状态就有可能和用它的日志恢复出来的库的状态不一致,为了保证写redo_log
和binlog
的一致性,实际采用了二阶段提交的方式。我们来看一下什么是二阶段提交?
-
InnoDB
存储引擎将更改更新到内存中后,同时将这个更新操作记录到redo
日志里面,此时redo日志处于prepare
状态; - 执行器生成这个操作的
binlog
,并将binlog
刷盘; - 执行器调用InnoDB的提交事务接口,
InnoDB
把刚刚写入的redo
日志改成commit
状态。至此,所有操作完成。
总结
以上就是文章的全部内容,对于一个SQL语句的更新来说,前面的流程跟一条SQL的查询流程是类似的,通过解析器进行语法分析,优化器优化,执行引擎去执行,这个都没有什么问题,唯一的不同的就是拿到符合条件的数据之后的操作,更新语句还涉及到两个重要的日志模块,那就是redo_log
、undo_log
和binlog
。
为了保证写redo_log
和binlog
的一致性,实际采用了二阶段提交的方式。
一条更新语句的执行过程可以总结如下: