在《面试官:你说说一条查询SQL的执行过程?》中描述了Mysql的架构分层,通过解析器、优化器和执行引擎完成一条SQL查询的过程,那这一篇续上继续说明一条更新SQL的执行过程。
对于一个SQL语句的更新来说,前面的流程都可以说类似的,通过解析器进行语法分析,优化器优化,执行引擎去执行,这个都没有什么问题,重点在于多了一点东西,那就是do_log、undo_log和binlog。
执行流程大致如下:
首先客户端发送请求到服务端,建立连接。服务端先看下查询缓存,对于更新某张表的SQL,该表的所有查询缓存都失效。接着来到解析器,进行语法分析,一些系统关键字校验,校验语法是否合规。然后优化器进行SQL优化,比如怎么选择索引之类,然后生成执行计划。执行引擎去存储引擎查询需要更新的数据。存储引擎判断当前缓冲池中是否存在需要更新的数据,存在就直接返回,否则去从磁盘加载数据。执行引擎调用存储引擎API去更新数据。存储引擎更新数据,同时写入undo_log、do_log信息。执行引擎写binlog,提交事务,流程结束。可以看到相比于查询流程,实际上更新多了关于undo_log和do_log的流程,接下来再具体探讨一下这几个流程的执行过程是什么样子。
do_logdo_log按照字面翻译称为重做日志,是InnoDB存储引擎特有的,用于保证事务的原子性和持久性。怎么理解呢?简单来说就是保存我们执行的更新语句的记录,如果服务器或者Mysql宕机,通过do_log可以恢复更新的数据。
按照上述流程来举例的话,比如updateusersetage=20wheid=1这样的简单更新SQL,我们不管执行引擎怎么拿到的数据,不管是从缓冲池拿的还是磁盘拿到的,这条现在数据都在缓冲池里面,然后去缓冲池的数据把age改成10。
缓冲池内存中的数据已经更新好了,那么接下来就该开始写do_log了,只是do_log也不是直接写文件的,一般都是这样对吧,直接写的话性能太差了,所以就有do_log_buffer叫做do_log缓冲。
在写do_log的时候先把数据写到do_log缓冲区,然后异步写入磁盘,很显然,极端情况下会有丢失数据的可能。
控制这个刷盘策略的的参数叫做innodb_flush_log_at_trx_