与查询流程不一样的是,更新流程涉及两个重要的日志模块,redo log(重做日志)和binlog(归档日志)
redo log
相当于暂时将修改记录写在缓存中,当缓存记录写满或者资源空闲的时候再记录到binlog,并且把已转移的记录清楚.因为每一次的更新操作都需要写进磁盘,然后磁盘也要找到对应的那条记录,然后再更新,整个过程 IO 成本、查找成本都很高。为了解决这个问题,MySQL 的设计者就用了这个思路来提升更新效率。其实这就是MySql里经常说到的WAL技术,WAL的全称是Write-Ahead Logging,它的关键点就是先写日志,再写磁盘.
InnoDB的redo log 是固定大小的,比如可以配置为一组4个文件,每个文件的大小是1gb,那么redo log总共可以记录4gb的操作.从头开始写,写到末尾就又回到开头循环写.
redo log 内部维护了两个指针一个是写指针(write pos),一个是检查指针(check point),write pos 一边写一边往后推,check point是当前要擦除的位置,也是往后推并且循环的,擦除记录前将记录更新到磁盘.而write pos 和check point之间就是目前redo log 还空着的部分.一旦write pos追上了check point,这时候就不能再执行新的更新了,得停下来将一部分数据擦除,并且写入磁盘.
有了redo log,InnoDB就可以保证即使数据库发生故障异常重启,之前提交的记录也不会丢失.这个能力称为crash-safe.
binlog
MySQL整体来看,有两块:一块是Server层,它主要是MySQL功能层面的事情,还有一块就是引擎层,负责存储相关的具体事宜.redo log是InnoDB引擎特有的日志,而Server层也有自己的日志,称为binlog
redo log和binlog区别
- redo log是InnoDB引擎特有的,binlog是MySQL的server层实现的,所有引擎都可以使用
- redo log是物理日志,记录的是"在某个数据项上做了什么修改".binlog是逻辑日志,记录的是这个语句的原始逻辑,比如 "给ID=2这一行的c字段加1"
- redo log 是循环写的,空间固定会用完,binlog是可以追加写入的.
接下来说说update的流程
- 执行器先找引擎取得ID=2这一行(这里查询缓存依旧生效).
- 执行器拿到行数据,并且将值+1得到新的一行数据,再调用引擎接口写入这行新数据.
- 引擎将这行新数据更新到内存中,同时将这个更新操作记录到redo log中,此时redo log处于prepare状态.然后告知执行器执行完成了,随时可以提交事务.
- 执行器生成这个操作的binlog,并把binlog写入磁盘
- 执行器调用引擎的提交事务接口,引擎把刚刚写入的redo log改成提交状态,更新完成.
redo log 的写入拆成了两个步骤:prepare 和 commit,这就是"两阶段提交"。