Mysql的innoDB存储引擎是怎么实现数据持久化的?一

    技术2025-05-13  10

    Mysql的innoDB存储引擎是怎么实现数据持久化的?一


    面试官:数据库的ACID属性了解吗?

    xx:就是原子性、一致性、隔离性、持久性。

    面试官:就没了?那你知道Mysql的innoDB存储引擎是怎么实现 D属性 持久性的呢?

    xx:这个是通过redo log保证。

    面试官:(又没了?)那你回去等通知吧。

    可能前两年的面试回答这个问题,用redo log回答已经可以了,不过现在的要求越来越高,显然搪塞不过去了。要想了解这个问题,首先要知道Buffer Pool。


    问题

    什么是Buffer Pool?

    Buffer Pool怎么提高读写效率?

    InnoDB以页(默认大小为16K)为单位,从磁盘文件中读取数据到内存。记录更新也是以页为单位刷新到磁盘中。每一页中的记录都是按照索引大小顺序排序。可以理解为Buffer Pool是在内存中缓存着某些页里的数据,事实上不仅仅缓存着页数据,还缓存着索引、自适应哈希索引、插入缓存(Insert Buffer)、锁、以及其他内部数据结构。

    如果没有Buffer Pool,读写效率为什么会低?

    模拟一个select查询场景(假设没有Buffer Pool)

    select * from order where order_id = 'xxx123';

    执行这个sql,InnoDB首先需要找到order_id = 'xxx123'这条记录所在的页,把这页读取到内存,然后从这页的所有记录中找到order_id = 'xxx123'那条记录返回。每次这样的查询搜索都会进行磁盘IO,而磁盘IO的速度相对于内存读写的速度、CPU计算的速度是很慢的。

    再模拟一个update更新场景(假设没有Buffer Pool)

    update order set user_name = '张三' where order_id = 'xxx123';

    同样的InnoDB首先需要找到order_id = 'xxx123'这条记录所在的页,把这页读取到内存,然后从这页的所有记录中找到order_id = 'xxx123'那条记录并更新user_name列为张三,再刷回磁盘。其中的查询搜索会进行磁盘IO,刷回磁盘的操作又出现随机写IO,就更慢了。

    所以显然,如果没有Buffer Pool,只是从磁盘读写的话,InnoDB的读写效率是极低的。《高性能Mysql第三版》P342也直接写到:InnoDB严重依赖Buffer Pool。

    当引入Buffer Pool之后,select查询场景时就会变成先在Buffer Pool中查找order_id = 'xxx123'这条记录所在的页,如果该页存在,则直接查询到记录返回,如果该页不存在,则从磁盘进行读取,放入Buffer Pool,返回记录。同样的,update更新场景时就会变成先在Buffer Pool中查找order_id = 'xxx123'这条记录所在的页,如果该页存在,则直接在该页上更新,如果该页不存在,则从磁盘进行读取,放入Buffer Pool,再在该页上更新。(这里还有一个写入redo log的过程)

    上面update场景下,时候磁盘中order_id = 'xxx123'对应的记录user_name还是"李四" ,而Buffer Pool中user_name则为“张三"。磁盘与Buffer Pool中不一致,这里Buffer Pool中的页就称为脏页。 当超过InnoDB缓冲池中最大允许的脏页面的比例,

    show VARIABLES like 'innodb_max_dirty_pages_pct';

    默认是75%,强制进行checkpoin,刷新一部分的脏页到磁盘。InnoDB默认通过一个后台线程来刷新脏页,并且会合并写入,更高效的顺序写出到磁盘;自适应刷新,无需等innodb_max_dirty_pages_pct的75%到了再刷新脏页,自行根据redo log的产生速度会优先刷新部分脏页

    show variables like 'innodb_adaptive_flushing';

    默认是开启的。

    这里还有一个问题,当Buffer Pool已经满了

    --查看Buffer Pool容量大小 show VARIABLES like 'innodb_buffer_pool_size';

    而有需要新的磁盘页加载到内存页该怎么做?这里也是使用到了LRU的算法思想,(我前面的文章有专门写LRU算法)将最近最少使用的页面淘汰,释放空间来加载新的页面。

    到这里就差不多把innoDB的读写效率高的原理讲完了,持久性还需要redo log来保证,redo log下期再写。

    扫码关注峡谷程序员![免费获取更多学习资料]

    Processed: 0.010, SQL: 9