MySQL InnoDB Buffer Pool
本文主要内容源自官网:MySQL :: MySQL 8.0 Reference Manual :: 15.5.1 Buffer Pool
感兴趣的可以直接阅读
缓冲池是主内存的一块区域,其中 InnoDB 访问表和索引数据时会在其中进行缓存。Buffer Pool 允许从内存中访问频繁使用的数据,这加快了处理速度。在专用服务器上,通常将多达 80% 的物理内存分配给 Buffer Pool。
为了大容量的读操作效率,Buffer Pool 被分为多个页面,这些页面可能包含多个行。为了缓存管理的效率,Buffer Pool 被实现为 Page 的链表。使用 LRU (Least Recently Used,最近最少使用)算法的变体将数据从缓存中老化淘汰出去。
知道如何利用 Buffer Pool,以将经常访问的数据保存在内存中是 MySQL 调整的重要方面。
缓冲池 LRU 算法
缓冲池 LRU 算法将缓冲池作为列表进行管理。当缓冲池空间不足,但有新页面需要添加到缓冲池时,将驱逐最近最少使用的页面,并将新页面添加到列表的 Midpoint(中点)。总列表分为两个子列表(Sublist):
最前面的是最近访问过的新页面(或者叫 young 页面,年轻页面)子列表
末尾是最近访问的旧页面的子列表

该算法将经常需要访问的页面保留在 New Sublist。Old Sublist 包含不常用的页面,这些页面是驱逐的候选对象。
通常情况,该算法遵循以下规则:
1. 的 Buffer Pool 用于 Old Sublist
列表的 Midpoint 是 New Sublist 的 Tail 和 Old Sublist 的 Head 相交的边界。
当 InnoDB 将页面读入缓冲池时,它首先将页面插入 Midpoint。通过用户触发的动作(比如 SQL 查询)或者预读操作可以对页面进行读取。
注意:官方这里说的读取(read)并不代表访问(access),请看下面。
- 访问(access)Old Sublist 中的页面会让其变得 young,然后将其移至 New Sublist 的 Head。如果是因为用户触发的动作需要读取页面,则将立即进行第一次 access,使页面 young。如果是由于预读操作而读取了该页面,则第一次 access 不会立即访问,甚至在页面离开之前都不会发生!
注意:预读未必会让页面变 young。
- 随着数据库的运行,通过将页面移动到列表的尾部,缓冲池中的页面将会“老化”。New 和 Old Sublist 都会随着其他页面的更新而老化。随着将页面插入 Midpoint,旧子列表中的页面也会老化。最终,未使用的页面到达子列表的尾部并被逐出。
注意:这里有个有趣的现象,页面是先插入到 Midpoint,而且这些页面插入之后属于 Old Sublist 的范围,所以他们很可能会马上“老化”,唯一让他们变得 young 的途径就是 access 一次。
默认情况下,查询(Query)读取的页面会立即移入新的子列表,这意味着它们在缓冲池停留的时间更长。
举个例子,mysqldump 操作或者 SELECT 不带 WHERE 子句的语句可能会将大量数据带入缓冲池,并驱逐出相当多的旧数据,即使加入 New Sublist Head 的新数据在 access 一次之后都不会再被使用了。同样,预读线程加载的页面,且仅仅访问过一次,那么也会移至 New Sublist 的开头。这些情况可能会将常用页面推到旧的子列表,然后被逐出。
所以,这似乎有个问题,有些 page 明明使用的频率不如其他页面,却可以插在其他页面前面,甚至逐出其他页面 ,官方给出了优化此行为的方法:让缓冲池的扫描具有“抵抗力”、配置 InnoDB 缓冲池预读(具体见官网)。
使用标准监视器监视 Buffer Pool
1 | ---------------------- |
若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏
扫描二维码,分享此文章