参考资料:
参考视频https://www.bilibili.com/video/BV1Pv411h7Ep?p=4&spm_id_from=pageDriver
?参考文章https://blog.csdn.net/Tomwildboar/article/details/121525187
1.背景知识:
- buffer pool 是innoDB的缓存区域,操作系统以及innoDB为了避免频繁的IO操作,磁盘到内存的数据都是以页为单位进行加载的,操作系统是4KB为一页,innoDB是16KB为一页,注意是将对应的页复制到内存中。
- ?当对数据库数据进行操作时,会先查询缓存(buffer pool)是否有该数据,没有就从磁盘中复制该数据页到内存中,然后进行操作。
- buffer pool每一个数据页 ,都有一个指向该数据页的的指针,我们叫控制块。
2.free链表
- buffer pool在经历反复的加载,冷数据淘汰后空置的区域是杂乱无章的,free 链表就是用来统计空置区域的。
- free 链表第一个节点叫基节点,存储着除基节点外,该链表一共有多少个节点,以及指向除基节点外,该链表的首节点以及尾节点
- free链表除首节点外,每个节点都存储着指向空闲区域(空闲页)
3.flush链表
- 内存(buffer pool)中,已经被修改,但是未及时持久化到磁盘中的数据页叫脏页。脏页会由后台程序按照一定的计划持久化到磁盘中。
- flush链表就是用来记录管理脏页的链表,和free链表一样,第一个节点叫基节点,存储着除基节点外,该链表一共有多少个节点,以及指向除基节点外,该链表的首节点以及尾节点
- flush 链表除首节点外,每一个节点都指向脏页,当后台程序进行持久化时,不需要扫描整个buffer pool,只需要从flush链表中获取就行。
4.lru链表?
- buffer pool内存是有限的,默认情况下是128M,但是每次对数据的操作都需要将数据从磁盘转移到内存中,这就需要我们将不常用的数据页定时的清除,以供新数据的存储。lru链表就是用来管理数据的冷热程度的。
-
4.1lru链表初版: - lru链表同free和flush链表一样,拥有一个基节点,最近一次使用的数据页置于基节点后的第一个节点,基节点后的控制块按照使用时间,由近至远排列。
- 当需要清理buffer pool时,就按照lru链表由链表尾到链表头依次进行清理。
- 但是这样会带来一个严重的问题,当执行语句? select *? from t1进行很大的全表扫描时,整个buffer pool都需要清空来为这次查询做缓存,包括之前很频繁使用的热点数据也需要清空,但是t1表仅仅使用这一次,之后就很少使用了,很明显这是不合理的。
?
-
4.2 lru链表终版? - 为了解决上述lru链表在进行大数据量查询时,不能保存热点数据的问题,对lru链表做了改进;
- 将lru链表分为热区和冷区(前5/8为热区后3/8为冷区)
-
4.2.1冷区 - 冷区的逻辑同lru原版,头部存储着最近使用数据页的控制块,按照使用时间,由近及远排列
- 当冷数据区已满,但是仍要插入控制块,就清理冷数据区尾部的控制块,然后将新的插入头部;
- 当冷区的控制块连续访问两次,且两次的间隔超过1秒,那么该控制块,就会转移到热区的头节点
- 之所以间隔1s,是因为控制块对应的数据页为16KB,扫描该数据页根本不需要1S,如果两次访问间隔超过1S,就认定为两次不同的访问,变为为热数据;
-
4.2.2热区 - 热区的数据全部来自于冷区的晋升,且按照使用的时间由近及远排序;
- 当热区的数据已满,但是仍然有冷区的数据晋升上来时,就将热区尾部的数据,放到冷区的头部,并将冷区晋升的数据放至热区头部;
-
4.2.3 淘汰机制 - 当进行大范围的数据查询时,buffer pool需要淘汰数据以保证内存够用,那么只会淘汰冷区的数据,热区不会淘汰,冷区循环使用。
?
?
|