关于新增操作要不要写入redo log?
厘清问题
本文所讨论的是新增(插入)操作(而不是更新操作)要不要写入redo log
背景
redo log有什么作用?
谈论到redo log避不开undo log。为了保证事务的原子性,当我们对数据表进行写操作时,需要记录它原先的值(undo log):
- 删除操作记录主键+全部内容
- 新增操作记录主键
- 更新操作记录主键+被修改的字段
但并不是每次操作,我们都会直接进行磁盘I/O。例如:当我们更新某条记录行或追加写undo log时,实际上我们操作的都是Buffer Pool(缓存池)中的数据页。
Buffer Pool的设计思想类似于内存缓存
为什么需要redo log?
我们的写操作,都是记录在Buffer Pool中,也就是写在内存中。
当事务提交后,若Buffer Pool中的数据页(标记为脏),还没有被刷入磁盘,那么发生宕机后,会导致数据丢失的问题,因此MySQL利用预写日志(Write-Ahead Logging)的方式来保证持久性或说是可靠性
或许这个原因并不太能说服我,例如:redo log也是写磁盘,在事务提交之后,直接写数据页到磁盘不就可以了吗?
-
将数据页刷到磁盘大概率是离散写;而将redo log刷到磁盘是连续写。二者在性能上有差异
-
因此在事务提交后,将redo log刷到磁盘即可
redo log实际上也是先写在缓存,再根据一定策略刷盘
疑惑从何而起?
由上面的 预写日志-流程图 可知:若Buffer Pool中未命中数据页,那么会先从磁盘中加载,然后写数据页并标记为脏,并将所做操作追加到redo log中
redo log的形式即:对 XXX 表空间中的 YYY 数据页 ZZZ 偏移量的地方做了AAA 更新
而如果我们做新增操作时,势必会影响到索引文件,也就是说,我们需要从磁盘中加载索引数据,然后找到合适的插入位置,并修改索引文件。
如果索引文件直接刷回磁盘,那么此时Buffer Pool中,该数据页不为脏!而redo log的意义主要是为了保证那些为脏的数据页,在事务提交后即使宕机也能够找回!
也就是说,如果新增操作所存放数据的数据页不为脏,那么redo log是不需要记录新增操作的!
实际上:
索引更新后(插入操作),不是立刻进行刷盘,而是在mysql 空闲的时候,会进行聚合写的优化,以避免多次随机 io,影响性能。
聚合写是指将多个写操作进行合并。MySQL会将需要刷新的脏数据页按照一定的策略进行排序,通常是按照数据页在磁盘上的位置进行排序,以实现顺序写。
所以MySQL先通过 redolog 顺序写,以保证事务的持久性。因此新增操作也需要写入redo log中!
总结:
在学习过程中应该把握事物之间的联系
- undo log是为了保证事务的原子性,在事务提交之前宕机,则会通过undo log恢复数据
- buffer pool的设计是为了调节磁盘和CPU之间的矛盾,但由于数据写在内存中,不具有可靠性,因此也需要通过redo log来保证事务的持久性
而我们新增数据时,也不会立刻将索引文件刷入磁盘,这严重加剧了磁盘和CPU之间的矛盾。实际上索引数据会缓存在Buffer Pool中的索引页中
因此,新增数据由于在Buffer Pool中是脏页,它也需要redo log来保证持久性!