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,速度会比较慢。

参考:https://juejin.cn/post/6976060698757595150

原文地址:https://www.cnblogs.com/kenLoong/p/15473664.html