执行流程

SQL的更新跟查询一样,会走同一套流程,即:

1
「连接器」->「分析器」->「优化器」->「执行器」

分析器知道SQL要做什么事情,优化器决定使用什么索引,执行器调用存储引擎进行具体执行。
与查询流程不同的是,更新流程涉及到日志模块:redo log和binlog

注:在一个表进行更新的时候,表相关的缓存会失效。

redo log

MySQL在数据进行更新的时候,采用了WAL技术(Write-Ahead Logging),先写日志,再写硬盘。

也就是说,有记录需要更新时,InnoDB引擎会先把记录写入redo log,然后更新内存,此时更新已算完成,等到系统空闲时,再讲操作记录更新到磁盘中。

redo log在InnoDB的大小是固定的(大小可以进行配置),可以看成是一个循环队列,这里面涉及到两个位置:

  • write pos,当前记录位置
  • check point,当前要擦除的位置

write pos一边写一边后移,check point在擦除记录时,要先把记录更新到数据文件中。
当redo log满了,也就是wrte pos追上check point,那么需要先停下来,擦除掉一些数据,把check point往前推进。

有了redo log,MySQL也就有了crash-safe的能力,即便数据库发生异常重启,数据也不会丢失。

binlog

redo log是InnoDB引擎特有的日志,Server层也有自己的日志:binlog(归档日志)。
最开始MySQL没有InnoDB引擎,而自带的引擎MyISAM没有crash-safe的能力,binlog日志只能用于归档。

redo log与binlog的区别:

  1. redo log是InnoDB引擎特有的;binlog是MySQL的Server层实现,所有引擎都可以使用;
  2. redo log是物理日志,记录:在某个数据页上做了什么修改;binlog是逻辑日志:记录语句的原始逻辑(比如为ID=2这行的c字段加1);
  3. redo log是循环写的,空间固定;binlog是追加写入的,不会覆盖以前的日志。

两阶段提交

要保证redo log和binlog的一致性,MySQL采用了「两阶段提交」:

  1. 当数据更新到内存时,先写入redo log,redo log处于prepare状态;
  2. 将binlog写入磁盘;
  3. 将redo log改为commit状态。

假如一份日志完成,另外一份日志未完成便crash时,采用两阶段提交,可以保证两份数据的一致性。

参考

「极客时间」-「MySQL实战45讲」