Mysql-持久性实现
Mysql数据增删改的一个大致过程如下:
- 先从索引中找到数据所在的
表空间ID
以及在表空间中的数据页的页号
- 然后通过
表空间ID+页号
作为Key,去缓存页哈希表
中查找Buffer Pool
是否已经加载了这个缓存页。如果已经加载了缓存页,就直接读取这个缓存页。 - 如果没有这个缓存页,就需要从磁盘表空间中加载数据页到内存,此时需要从
Free链表
获取一个空闲页加入LRU链表
中,加载的数据页就会放到这个空闲的缓存页中。 - 接着在对应的缓存页中执行增删改操作,被修改过的缓存页就变成了脏页,会加入
Flush链表
中。 - 最后,后台线程会在一些时机将
LRU链表
尾部的冷数据和Flush链表
中的脏页刷盘。
这个过程有个最大的问题就是,数据修改且事务已经提交了,但只是修改了Buffer Pool中的缓存页,数据并没有持久化到磁盘,如果此时数据库宕机,那数据不就丢失了!
但是也不可能每次事务一提交,就把事务更新的缓存页都刷新回磁盘文件里去,因为缓存页刷新到磁盘文件里是随机磁盘读写
,性能是很差的,这会导致数据库性能和并发能力都很差。
所以此时就引入了一个 redo log
机制,在提交事务的时候,先把对缓存页的修改以日志的形式,写到 redo log 文件
里去,而且保证写入文件成功才算事务提交成功。而且redo log
是顺序写入
磁盘文件,每次都是追加
到磁盘文件末尾去,速度是非常快的。之后再在某个时机将修改的缓存页刷入磁盘,这时就算数据库宕机,也可以利用redo log
来恢复数据。
随机磁盘读写:一个事务里的SQL可能牵涉到多个数据页的修改,而这些数据页可能不是相邻的,也就是属于随机IO。显然操作随机IO,速度会比较慢。