InnoDb存储引擎执行流程
缓冲池 buffer pool
- 会把一些磁盘上的数据加载到该内存当中
- 查询数据的时候不从磁盘查,从该内存里查
undo log
- 逻辑日志,可以认为当delete一条记录时,undo log中会记录一条对应的insert记录,反之亦然,当update一条记录时,它记录一条对应相反的update记录
- 用于数据回滚
- 实现mvcc
redo log
- 存储引擎层日志
- 物理日志(类似于“对哪个数据页中的什么记录,做了个什么修改”)
- 记录对数据做了什么修改,防止已提交事务的数据丢失。因为数据不是实时刷盘的,数据是在buffer pool当中,如果数据库宕机了并且buffer pool中的数据还没有刷盘,修改过的数据就丢失了,redo log解决这一问题
- redo log buffer是redo log的缓冲区,数据做了什么修改,首先会写入到redo log buffer中,再刷盘写入redo log中
binlog
- 归档日志,属于mysql server层,不属于存储引擎层
- 逻辑性日志(类似于“对users表中的id=10的一行数据做了更新操作,更新以后的值是什么”)
事务还没有提交,mysql宕机了怎么办?
- 事务没有提交,mysql宕机,buffer pool和redo log buffer中的数据都会丢失,数据库返回异常,提示事务失败
- 磁盘上的数据没有任何变化,不影响
redo log刷盘策略
- 当提交事务的时候,redo log buffer里的数据会根据一定规则刷到磁盘上
- 通过innodb_flush_log_at_trx_commit参数来配置
- 0 提交事务的时候,不立即把 redo log buffer 里的数据刷入磁盘文件的,而是依靠 InnoDB 的主线程每秒执行一次刷新到磁盘。此时可能你提交事务了,结果 mysql 宕机了,然后此时内存里的数据全部丢失
- 1 提交事务的时候,就必须把 redo log 从内存刷入到磁盘文件里去,只要事务提交成功,那么 redo log 就必然在磁盘里了
- 2 提交事务的时候,把 redo 日志写入磁盘文件对应的 os cache 缓存里去,而不是直接进入磁盘文件,可能 1 秒后才会把 os cache 里的数据写入到磁盘文件里去。此时mysql宕机,数据不会丢失;如果机器宕机,数据会丢失
binlog刷盘策略
- 当提交事务的时候,binlog也会刷到磁盘上去
- 通过sync_binlog参数来配置
- 0 默认值。事务提交后,将二进制日志写入了操作系统缓冲,若操作系统宕机则会丢失部分二进制日志
- 1 事务提交后,将二进制文件写入磁盘并立即执行刷新操作,相当于是同步写入磁盘,不经过操作系统的缓存
执行一条更新sql语句,存储引擎执行流程
- 把该行数据从磁盘加载到buffer pool中
- 对该行数据进行加锁
- 写undo log
- 在buffer pool当中更新数据
- 把所作的修改写入到redo log buffer当中
- 准备提交事务redolog刷盘
- 准备提交事务binlog刷盘
- 把binlog的文件名和位置写入commit标记,commit标记写入redolog中,事务才算提交成功;否则不会成功
commit标记的意义
- redo log刷盘成功,binlog还没刷盘,数据库宕机,没有commit标记写到redo log中,事务判定为失败。因为redolog中有这次更新日志,binlog中没有这次更新日志,会出现数据不一致问题
- redo log刷盘成功,binlog刷盘成功,commit标记还没来得及写入redo log中,数据库宕机,同样判定事务提交失败
- commit写入redo log,才能判定事务成功;因为此时,redo log中有这次更新记录,binlog也有这次更新记录,redo log和binlog保持了一致
内存(buffer pool)中更新过脏数据什么时候刷盘?
- 后台io线程有时间会把内存buffer pool中更新过的脏数据(因为更新过,和磁盘上的数据不一样,所以叫脏数据)刷回到磁盘上,哪怕这时候mysql宕机,也没有关系,可通过redo log和binlog恢复数据到内存中,io线程有时间再把数据刷盘
执行更新sql语句存储引擎执行流程总结
- 执行阶段
- 数据加载到内存,写undo log,更新内存中数据,写redo log buffer
- 事务提交阶段
- redo log和binlog刷盘,commit标记写入redo log中
- 最后
- 后台io线程随机把内存中脏数据刷到磁盘上
文章和图片参考 救火队长mysql