MySQL Buffer Pool深度解析:当缓存页不足时如何基于LRU算法进行淘汰

1. 问题引入:free链表空了怎么办?

在之前的文章中,我们详细讲解了MySQL Buffer Pool中缓存页的划分、free链表的管理,以及数据页从磁盘加载到缓存页的过程。今天我们来分析一个更实际的问题:当Buffer Pool中的空闲缓存页用完时,系统该如何处理?

1.1 缓存页耗尽的必然性

随着数据库持续运行,不断有数据页从磁盘加载到Buffer Pool中:

  • 每次数据加载都会从free链表获取一个空闲缓存页
  • free链表中的节点会越来越少
  • 最终必然出现free链表为空的情况
markdown 复制代码
磁盘数据页 → 查找free链表 → 获取空闲缓存页 → 加载数据

当free链表耗尽时,新的数据页将无法加载,此时必须淘汰部分现有缓存页

2. 淘汰策略:该把谁"请"出内存?

2.1 什么是淘汰缓存页?

淘汰缓存页是指:

  1. 将被修改过的缓存页数据刷新到磁盘(如果它是脏页)
  2. 清空该缓存页
  3. 将其重新加入free链表,变为可用状态

这个过程确保了内存资源的循环利用,但引出一个关键问题:应该淘汰哪些缓存页?

3. 核心指标:缓存命中率

为了做出最优淘汰决策,MySQL引入了缓存命中率的概念:

场景 访问频率 命中率评估 淘汰优先级
缓存页A 100次请求中30次访问 高命中率 保留
缓存页B 加载后仅访问1次,后续100次请求无访问 低命中率 优先淘汰

核心原则:优先淘汰"占着茅坑不拉屎"的缓存页------即那些长期不被访问却占用内存资源的页面。

4. LRU链表:智能淘汰的指挥官

4.1 LRU基本概念

MySQL通过LRU链表(Least Recently Used,最近最少使用)来实现智能淘汰:

工作原理:最近被访问的缓存页移动到链表头部,久未访问的页面自然沉降到尾部。

4.2 LRU链表运作机制

数据加载时

当从磁盘加载数据页到缓存页:

  • 将该缓存页的描述信息块放入LRU链表头部
  • 表示这是最新被使用的页面
markdown 复制代码
[新加载的缓存页] → LRU Head → ... → LRU Tail
数据访问时

当查询或修改某个已存在的缓存页:

  • 无论该缓存页在LRU链表的哪个位置
  • 立即将其移动到链表头部
  • 表示它刚被访问过,近期可能再次被访问
markdown 复制代码
LRU Tail中的缓存页被访问 → 移动到LRU Head
淘汰决策时

当需要腾出空闲缓存页:

  • 直接从LRU链表尾部选取
  • 尾部的页面就是"最近最少使用"的页面
  • 将其刷新到磁盘后清空

5. 技术图解

图1:free链表耗尽的场景

复制代码
Buffer Pool (128MB)
┌─────────────────────────────────────┐
│ [数据] [数据] [数据] ... [数据]          │
│ 缓存页  缓存页  缓存页      缓存页      │
└─────────────────────────────────────┘
        ▲
        │ 无法加载新数据页
        │
磁盘文件 ────────────→ X (无空闲缓存页)

图2:LRU链表驱动的淘汰流程

复制代码
1. 识别LRU链表尾部页面(最少使用)
   ↓
2. 如果是脏页,刷新到磁盘
   ↓
3. 清空缓存页,加入free链表
   ↓
4. 加载新数据页到腾出的空间
   ↓
5. 新页面插入LRU链表头部

6. 思考题解答:表/行 vs 表空间/数据页

问题:SQL中的表、行与表空间、数据页之间是什么关系?

答案

  • 逻辑概念:表、列、行------面向开发者的抽象,关注数据结构
  • 物理概念:表空间、数据页------面向存储的实现,关注数据在磁盘的组织方式

类比

就像你看一本书,只关注"章节"和"段落"(逻辑),而不必关心"纸张"和"印刷墨迹"(物理)。数据库自动将逻辑结构映射为物理存储。

7. 总结要点

  1. free链表耗尽是常态:持续的数据加载必然导致空闲页用完
  2. LRU是淘汰依据:通过访问时间戳智能判断页面热度
  3. 头部-尾部机制:热点数据在头部,冷数据自然沉降尾部
  4. 性能保障:确保内存中保留的都是高价值数据,最大化缓存命中率

系列预告:下一篇文章将深入探讨MySQL LRU算法的优化细节,包括如何解决"全表扫描污染缓存"等经典问题。

参考资料:《MySQL专栏》

版权说明:本文内容整理自狸猫技术窝MySQL专栏,仅供学习交流使用。

相关推荐
一枚正在学习的小白2 小时前
prometheus监控mysql服务
linux·运维·mysql·prometheus
丁丁丁梦涛2 小时前
navicat跨服务器连接MySQL数据库
服务器·数据库·mysql
tgethe2 小时前
mysql-索引详解
数据库·mysql
子夜江寒2 小时前
MySQL 学习
数据库·mysql
wepe122 小时前
FlyEnv---phpstudy平替
java·python·mysql·nginx·php
soft20015252 小时前
MySQL Buffer Pool深度解析:冷热数据分离下的LRU链表工作机制
数据库·mysql·链表
过期动态14 小时前
JDBC高级篇:优化、封装与事务全流程指南
android·java·开发语言·数据库·python·mysql
一位代码14 小时前
mysql | 常见日期函数使用及格式转换方法
数据库·mysql
杰克尼15 小时前
mysql_day01
数据库·mysql