MySQL的SQL更新语句是怎么执行的
执行流程
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的区别:
- redo log是InnoDB引擎特有的;binlog是MySQL的Server层实现,所有引擎都可以使用;
- redo log是物理日志,记录:在某个数据页上做了什么修改;binlog是逻辑日志:记录语句的原始逻辑(比如为ID=2这行的c字段加1);
- redo log是循环写的,空间固定;binlog是追加写入的,不会覆盖以前的日志。
两阶段提交
要保证redo log和binlog的一致性,MySQL采用了「两阶段提交」:
- 当数据更新到内存时,先写入redo log,redo log处于prepare状态;
- 将binlog写入磁盘;
- 将redo log改为commit状态。
假如一份日志完成,另外一份日志未完成便crash时,采用两阶段提交,可以保证两份数据的一致性。
参考
「极客时间」-「MySQL实战45讲」
- 本文链接:https://keepmoving.ren/database/mysql/how-to-execute-update-sql/
- 版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 CN 许可协议。转载请注明出处!