如何理解MySQL的Buffer Pool

60次阅读
没有评论

共计 2519 个字符,预计需要花费 7 分钟才能阅读完成。

本篇内容介绍了“如何理解 MySQL 的 Buffer Pool”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让丸趣 TV 小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

前言

buffer pool 是什么

咱们在使用 mysql 的时候,比如很简单的 select * from  table; 这条语句,具体查询数据其实是在存储引擎中实现的,大家都知道 mysql 数据其实是放在磁盘里面的,如果每次查询都直接从磁盘里面查询,这样势必会很影响性能,所以一定是先把数据从磁盘中取出,然后放在内存中,下次查询直接从内存中来取。但是一台机器中往往不是只有 mysql 一个进程在运行的,很多个进程都需要使用内存,所以 mysql 中会有一个专门的区域来处理这些数据,这个专门为 mysql 准备的区域,就叫 buffer  pool。

buffer pool 的工作流程

咱们以查询语句为例 1: 在查询的时候会先去 buffer pool(内存) 中看看有没有对应的数据页,如果有的话直接返回 2: 如果 buffer  pool 中没有对应的数据页,则会去磁盘中查找,磁盘中如果找到了对应的数据,则会把该页的数据直接 copy 一份到 buffer pool 中返回给客户端  3: 下次有同样的查询进来直接查找 buffer pool 找到对应的数据返回即可。

大家看到这里相信应该对 buffer pool 有了个大概的认识,有没有感觉有点缓存的感觉,当然 buffer  pool 可没有缓存那么简单,内部结构还是比较复杂的,不过没关系,咱们继续往下看。

buffer pool 数据管理

数据管理的基本单位

buffer pool 毕竟是一种内存管理,数据当然不是按照一条一条的 sql 语句来管理的,而是按照数据页来管理的,innodb   引擎默认的数据页是 16kb,而 buffer  pool 启动的时候是默认的 128M,所以是有 8192 个数据页的。而磁盘的数据管理也是用数据页为单位来管理的,所以每次查找数据的时候,先请求 buffer  pool,buffer pool 中没有的话会到磁盘中找到对应的数据页,然后 copy 到 buffer pool 中给客户端返回。

free 链表

正常情况下,buffer  pool 肯定是从第一个数据页,不断的往后填充的,一个一个的往后写入, 每次直接在后面追加就可以了。如下图 (黄色部分表示已经写入数据)

但是实际生产环境中,并不是这样的,我们不光有查询操作,还有删除,修改等操作,而且已经写入 buffer  pool 的数据不一定是始终有价值的,有一些数据是不需要的,需要释放对应的数据页的,所以就会造成 buffer  pool 的数据其实是这种情况,间断不连续的。

在这种情况下该如何去找到有效的空闲的数据页空间来存储数据呢? 最直观的方法就是从第一个页遍历的一个一个的往后找,找到空闲的数据页即可,这种方法倒是可行,但是非常影响效率,所以 mysql 在处理这种问题用上了 free 链表的方式来管理空闲的数据页。

大家可以看一看 free 链表的结构

free 链表有一个基节点,记录了该 free 链表的唯一标志,该链表的尾节点地址,以及链表的总长度

基节点后面会有很多的控制块,控制块本身很小,只是存储了指向空闲数据页的指针而已,所以 buffer  pool 在寻找空闲数据页的时候直接用 free 链表可以直接找到。

只要有一页数据空闲出来之后,直接把该数据页的地址追加到 free 链表即可。

flush 链表

当然只是用 free 链表是解决不了所有问题的,比如:我们在执行 update table test set field_a =  1; 的时候,我们是先修改 buffer pool 里面对应的数据页,然后再更新磁盘中对应的数据页的,(当然这里会涉及到一个数据一致性的问题,mysql 是用 redo  log 解决的,这个不在咱们这篇文章的讨论范围之内) 我们把 buffer  pool 中对应修改的数据页同步修改到磁盘的时候,这个过程称之为 刷脏 , 刷脏是有一定策略的,可以用

select @@innodb_flush_log_at_trx_commit;

来查看刷脏策略

我们一般都不会设置实时写,这样很影响性能,所以一般都是延迟写的,那么就会引发一个问题,mysql 是如何在 buffer  pool 中找到被修改过的脏数据的呢? 这里咱们就用上了 flush 链表了,其实和 free 链表比较像

flush 链表上面维护的都是脏数据页的指针。刷脏的时候直接遍历 flush 链表去刷脏就可以了。

lru 链表

buffer  pool 是有一定空间限制的,默认是 128M,总会有空间塞满的时候的,所以数据页是有淘汰机制的,淘汰机制就是 lru(最近最少使用)。

lru 原理其实也很简单,使用到过的数据页,直接移动到链表的头部,然后在 buffer  pool 满了之后直接淘汰掉链表尾部的数据页就可以了。

lru 链表的优化

其实简单的 lru 链表是存在一定的问题的,比如咱们在工作过程中,可能会用上 select * from  test 这样的语句来进行一些刷数据等需求,如果 test 表是非常大的,很有可能一下子把 buffer  pool 占满,把之前的数据页全部都淘汰掉,然后其余的数据在线上业务正常执行的时候,又会回来重新把之前 select * from test   占用的数据页重新慢慢淘汰掉,这一来一去是非常影响线上的性能的。

所以鉴于以上所在的问题,mysql 的 buffer pool 是在 lru 的基础上进行了一些优化的。

buffer pool 的 lru 链表把数据分为了热数据块和冷数据块,比例大概 5:3 的样子,每次新的数据页写入都会写入冷数据区。

但是如果这样的话那么热数据区永远都不会有数据,所以冷数据区写入的时候会另外记录上写入的时间,下次访问该数据区的时候如果时间间隔大于 1s, 那么就会放入热数据区,这样就不会淘汰掉大量的无辜数据。所以我们在执行 select  * from test 这种语句刷新脚本的时候,只会占用冷数据的空间,而不会影响到热数据。

“如何理解 MySQL 的 Buffer Pool”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注丸趣 TV 网站,丸趣 TV 小编将为大家输出更多高质量的实用文章!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-27发表,共计2519字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)