一文了解MySQL缓冲池buffer pool(作用 原理 淘汰策略 分配 刷新 配置)

对于MySQL的读请求来说,InnoDB维护了一个缓冲池 buffer pool,避免每次查询数据都进行磁盘IO,有效地减少了磁盘IO,提升了性能。

作用

缓冲池存储了最近访问或经常访问的数据页和索引页,当查询操作需要读取数据时,InnoDB首先在缓冲池里查找所需的页,如果找到了(命中),则无需访问磁盘,这样可以大大减少数据访问的延迟。

todo:缓冲区还缓存了最近修改的数据,这些数据在合适的时机会被写回到磁盘上,这个过程称为刷盘flush或写入write

工作原理

当一个数据页被访问的时候,会被加载到缓冲池里。如果该页已经在缓冲池中,则直接使用;如果不在,则在磁盘读取并放入缓冲池。

InnoDB会管理和淘汰缓冲池中的页,来保证只把最热的数据放在最近的地方,以最大限度地降低磁盘访问

管理与淘汰

预读

磁盘读取数据地时候是按页读取,一次至少读一页数据,一般是4K,如果未来要读取地数据就在页中,能够省去后续地磁盘IO,提高效率。这是因为局部性原理,数据访问一般都遵循集中读写的原则,使用一些数据,大概率会使用附近的数据。

所以,缓冲池一般也是按页缓存数据,把一些可能要访问的页提前加入缓冲池,避免未来的磁盘IO操作。

这里能想到的一点就是 缓存这边的预缓存策略。比如社区里返回一篇文章和下面的评论,把第一层评论的所有评论缓存一下。

那么InnoDB是用什么算法管理缓冲页的?

传统LRU

把入缓冲池的页放到LRU的头部,作为最近访问的元素,从而最晚被淘汰。

如果页已经在缓冲池里,就移动到LRU头部,没有页被淘汰;

如果页不在缓冲池里,放入LRU头部,淘汰LRU尾部页

但是这种算法用在MySQL这里就有2个问题:预读失效和缓冲池污染

预读失效

提前把页放入了缓冲池但是实际上并没有从页中读取数据

如何解决?

让预读失败的页,停留在缓冲池LRU里的时间尽可能短

让真正被读取的页,才能挪到缓冲池LRU的头部,这样可以保证真正被读取的热数据保留在缓冲池的时间尽可能长

具体方法

将LRU分为新生代和老生代两个部分,新老生代首尾相连,即,新生代后面是老生代

新页(例如被预读地页)加入缓冲池时,只加入到老生代头部

如果数据真正被读取(预读成功),才会被加入到新生代的头部

如果没有被读取,会币新生代的热数据页更早被淘汰出缓冲池

但是这样依旧解决不了缓冲池污染

缓冲池污染

当某一个SQL语句,需要批量扫描大量数据时,可能导致把缓冲池所有页都替换出去,导致大量热数据被换出,MySQL性能急剧下降

在扫描的时候,所有的数据页都会被加到新生代头部,但是只访问一次,真正的热数据被大量换出

如何解决?

使用老生代停留时间窗口的机制,假设T为老生代停留时间窗口,插入老生代头部的页,即使立刻被访问,也不会立刻被放入新生代头部。只有满足被访问并且在老生代停留时间大于T,才会被放入到新生代头部。

缓冲池的分配

缓冲池被划分为多个缓冲块Buffer Blocks,每个缓冲块通常为一页,页大小默认为16KB

缓冲池中的页可以是热页(频繁访问的页)或冷页(不常访问的页),InnoDB会根据访问频率动态调整这些页在缓冲池中的位置。

缓冲池的刷新

为了保证数据的持久性,InnoDB会定期将缓冲池中脏页(被修改的页)刷新回磁盘,这个过程可以通过多种方式触发,包括手动刷新、自动刷新、缓冲池满的页替换等

缓冲池的监控

SHOW ENGINE INNODB STATUS命令来查看缓冲池的当前状态

缓冲池实例

在多实例环境中,每个InnoDB实例都有自己的缓冲池,从MySQL5.7开始,支持多个缓冲池实例

缓冲池的配置和优化

缓冲池的大小和配置需要根据实际的工作负责和可用内存进行调整

innodb_buffer_pool_size:配置缓冲池的大小,在内存允许的情况下,DBA往往会建议调大这个参数,越多数据和索引放到内存里,数据库的性能会越好

innodb_old_blocks_pct:老生代占整个LRU链长度的比例,默认是37,即整个LRU中新生代与老生代长度比例是63:37。

innodb_old_blocks_time:老生代停留时间窗口,单位是毫秒,默认是1000,即同时满足"被访问"与"在老生代停留时间超过1秒"两个条件,才会被插入到新生代头部

相关推荐
S-X-S几秒前
SQL美化器优化
数据库·sql
老大白菜1 分钟前
VB.NET 正则表达式完全指南
mysql·正则表达式·.net
Whacky-u1 分钟前
Hive SQL必刷练习题:连续问题 & 间断连续
大数据·数据库·数据仓库·sql
Lang_xi_2 分钟前
汇总统计数据--SQL中聚集函数的使用
数据库·mysql
全镇人的希望2 分钟前
oarcle执行报错提示:SQL 错误 [1839] [22008]: ORA-01839: 指定月份的日期无效问题解决
数据库·sql
百香果果ccc4 分钟前
SQL中的公用表表达式
数据库·sql
落霞的思绪7 分钟前
苍穹外卖08——(涉及接收日期格式数据、ApachePOI导出报表、sql获取top10菜品数据)
java·spring boot·后端·mybatis·苍穹外卖
基哥的奋斗历程27 分钟前
Docker与微服务实战2-基础篇
docker·微服务·架构
徐礼昭|商派软件市场负责人35 分钟前
支持各大平台账单处理,支持复杂业财数据的精细化对账|商派OMS
大数据·数据库·人工智能·oms·财务对账
昔我往昔43 分钟前
Spring Boot项目中如何使用日志记录
java·spring boot·后端