一文搞懂MySsql的Buffer Pool

Buffer Pool是什么

Buffer Pool是MySQL数据库中一个非常关键的组件。数据库中的数据最终都是存放在磁盘文件上的。但是在对数据库执行增删改查操作时,不可能直接更新磁盘上的数据。因为如果直接对磁盘进行随机读写操作,那速度是相当的慢的。随便一个大磁盘文件的随机读写操作,可能都要几百毫秒,这样数据库每秒也就只能处理几百个请求。

数据库执行增删改操作时,是基于内存Buffer Pool中的数据进行的。同时为了防止在更新完内存中的数据之后,由于机器宕机而造成数据丢失,数据库引入了redo日志机制,即增删改时会把修改也写入redo日志中。

Buffer Pool就是数据库的一个内存组件,里面缓存了磁盘上的真实数据。当执行更新时,会写undo日志、修改Buffer Pool数据、写redo日志;当提交事务时,会将redo日志刷磁、binlog刷盘、添加commit标记。最后后台IO线程会随机把Buffer Pool里的脏数据刷入到磁盘数据文件中。 

为什么要有 Buffer Pool?

虽然说 MySQL 的数据是存储在磁盘里的,但是也不能每次都从磁盘里面读取数据,这样性能是极差的。

要想提升查询性能,加个缓存就行了嘛。所以,当数据从磁盘中取出后,缓存内存中,下次查询同样的数据的时候,直接从内存中读取。

为此,Innodb 存储引擎设计了一个缓冲池(Buffer Pool,来提高数据库的读写性能。

有了缓冲池后:

  • 当读取数据时,如果数据存在于  Buffer Pool 中,客户端就会直接读取  Buffer Pool 中的数据,否则再去磁盘中读取。

  • 当修改数据时,首先是修改  Buffer Pool  中数据所在的页,然后将其页设置为脏页,最后由后台线程将脏页写入到磁盘。

如何配置Buffer Pool的大小 

由于Buffer Pool本质就是数据库的一个内存组件,所以Buffer Pool是有大小的,不能无限大。

Buffer Pool的默认大小是128MB,有点偏小。在实际生产环境下可以对Buffer Pool进行调整。比如对于16核32GB的数据库,可以给Buffer Pool分配2GB大小的内存。

[server]innodb_buffer_pool_size = 2147483648

 Buffer Pool 缓存什么?

InnoDB 会把存储的数据划分为若干个「页」,以页作为磁盘和内存交互的基本单位,一个页的默认大小为 16KB。因此,Buffer Pool  同样需要按「页」来划分。

在 MySQL 启动的时候,InnoDB 会为 Buffer Pool 申请一片连续的内存空间,然后按照默认的16KB的大小划分出一个个的页, Buffer Pool 中的页就叫做缓存页。此时这些缓存页都是空闲的,之后随着程序的运行,才会有磁盘上的页被缓存到 Buffer Pool 中。

所以,MySQL 刚启动的时候,你会观察到使用的虚拟内存空间很大,而使用到的物理内存空间却很小,这是因为只有这些虚拟内存被访问后,操作系统才会触发缺页中断,接着将虚拟地址和物理地址建立映射关系。

Buffer Pool  除了缓存「索引页」和「数据页」,还包括了 undo 页,插入缓存、自适应哈希索引、锁信息等等。

为了更好的管理这些在 Buffer Pool 中的缓存页,InnoDB 为每一个缓存页都创建了一个控制块,控制块信息包括「缓存页的表空间、页号、缓存页地址、链表节点」等等。

控制块也是占有内存空间的,它是放在 Buffer Pool 的最前面,接着才是缓存页,如下图:

上图中控制块和缓存页之间灰色部分称为碎片空间。

为什么会有碎片空间呢?

 

你想想啊,每一个控制块都对应一个缓存页,那在分配足够多的控制块和缓存页后,可能剩余的那点儿空间不够一对控制块和缓存页的大小,自然就用不到喽,这个用不到的那点儿内存空间就被称为碎片了。

当然,如果你把 Buffer Pool 的大小设置的刚刚好的话,也可能不会产生碎片。

查询一条记录,就只需要缓冲一条记录吗?

不是的。

当我们查询一条记录时,InnoDB 是会把整个页的数据加载到 Buffer Pool 中,因为,通过索引只能定位到磁盘中的页,而不能定位到页中的一条记录。将页加载到 Buffer Pool 后,再通过页里的页目录去定位到某条具体的记录。

free链表可判断哪些缓存页是空闲的

当数据库运行起来后,肯定会不停地进行增删改查操作。此时会从磁盘上读取一个个的数据页放入到Buffer Pool中的缓存页里。

默认情况下,磁盘上的数据页和缓存页是一一对应的,都是16KB。Buffer Pool把数据缓存起来后,就可以对数据在内存里执行增删改查。

但是当数据库从磁盘上读取数据页放入Buffer Pool中的缓存页时,首先需要解决一个问题:哪些缓存页是空闲的?

为此,数据库为Buffer Pool设计了一个free链表,它是一个双向链表。在这个free链表里,每个节点就是一个空闲缓存页的描述数据块的地址。只要一个缓存页是空闲的,则其描述数据块的地址就会被放入free链表中。所以数据库刚启动时,如果此时所有的缓存页都是空闲的,那么所有缓存页的描述数据块就会被放进该free链表里。

简单LRU链表的工作原理

假设InnoDB从磁盘加载一个数据页到缓存页时,就把这个缓存页的描述数据块放到LRU链表头部去。

那么只要一个缓存页有数据,那么该缓存页就会在LRU里。并且最新加载数据的缓存页,会被放到LRU链表的头部。

假设某个缓存页的描述数据块本来在LRU链表的尾部,后面只要查询或者修改了这个缓存页的数据,也会把其描述数据块挪动到LRU链表头部。

总之,就是保证最近被访问过的缓存页,一定在LRU链表的头部。这样当缓冲区没有空闲的缓存页时,可以在LRU链表尾部找一个缓存页。而这个缓存页就是最近最少被访问的那个缓存页。然后把LRU链表尾部的那个缓存页刷入磁盘从而腾出一个空闲的缓存页,最后把需要的磁盘数据页加载到这个空闲的缓存页中即可。

这个LRU链表需要一定长度,不能只有2个节点。否则如果先是节点1被访问100次,接着到节点2被访问。这样虽然链表尾部是节点1,但实际上节点1是最近最少被访问的。

简单LRU链表可能存在的预读问题

在LRU链表的尾部,一定是最近最少被访问的那个缓存页。但这个LRU机制在实际运行中,面对MySQL的预读机制,会有问题。

MySQL预读,指的是从磁盘加载一个数据页时,可能会连带着把这个数据页相邻的其他数据页,也加载到缓存里。比如现在有两个空闲缓存页,在加载一个数据页时,就会连带着把其相邻的一个数据页也加载到缓存里去。但是接下来只有一个缓存页被访问了,另外一个通过预读机制加载的缓存页,其实并没被访问,而此时这两个缓存页可能都在LRU链表前面。

触发MySQL预读机制的情况

情况一:参数innodb_read_ahead_threshold默认值是56,意思是如果顺序访问一个区的多个数据页的数量超过了该阀值。就会触发预读机制,把下一个相邻区中的所有数据页都加载到缓存里去。

情况二:Buffer Pool里缓存一个区13个连续的会被频繁访问的数据页,此时就会直接触发预读机制,把这个区里的其他数据页也加载到缓存里。该情况通过参数innodb_random_read_ahead控制,默认OFF表示关闭。

所以,默认情况下第一种情况很可能会触发预读机制。并且第一种情况会一下子把相邻区中很多数据页加载到缓存里。这些缓存页如果都放在LRU链表前面,并且没什么访问了。这样就会导致一些频繁被访问的缓存页放到了LRU链表的尾部。最后造成频繁被访问的缓存页反而被清空掉。而被清空掉的缓存页很快又要从磁盘中重新加载进入缓冲区。这时不但不合理还很影响性能。

简单LRU链表可能存在的全表扫描问题

全表扫描,就是类似于执行这样的SQL语句:select * from users。此时没有加任何一个where条件,这个会导致MySQL把该表所有的数据页,都从磁盘加载到Buffer Pool里。

这时LRU链表中排在前面的缓存页,可能都是全表扫描加载进来的缓存页。而如果这次全表扫描后,后面几乎没有用到这个表里的数据。那此时LRU链表的尾部,也可能都是之前一直被频繁访问的缓存页。这样也会把频繁访问的缓存页给淘汰掉,最后留下不经常访问的全表扫描加载进来的缓存页。

总结

所以如果使用简单的LRU链表机制,其实是漏洞百出的。因为预读机制、全表扫描会把未来并不经常访问的数据页加载到缓存页里,从而导致那些频繁被访问的缓存页不得不处于LRU链表尾部。如果此时恰好需要把一些缓存页刷入磁盘或者清空以腾出空闲的缓存页,那么就会把频繁被访问的缓存页给清空了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/866340.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

软考(高项)系统分析师--论文写作技巧

文章目录 前言一、论文的结构和要求:1.1 论文的结构:1.2 论文的要求: 二、论文每段的写法:2.1 解题:2.2 摘要:2.2.1 第一段:2.2.2 第二段: 2.3 正文:2.3.1 项目背景&…

TikTok美区日销二十万美金爆款黑马!胸贴赛道成功起飞!

从去年开始,一项名为“No bra”(无胸罩)的挑战就长期刷屏TikTok。随着平台内各大博主和明星站台发声,越来越多用户也参与其中,话题的热度逐渐走向高潮。截止到目前, TikTok上相关话题累计播放量已高达8.3亿…

django admin添加自己的页面

建立模型 如果要单独建一个页面,用于展示model的数据,可以新建一个model,继承自要展示的那个类 class ViewsByDayModel(ViewsByDay): # 父类为要展示的model类class Meta:proxy True # 使用代理verbose_name 每日浏览次数统计verbose_nam…

仿Antd-mobile的Cascader实现省市区联动

为啥不直接用Cascader 级联选择组件呢?主要是因为作为老项目,已经引入了antd-mobile2.3.4,同时引入v5版本会有兼容性问题。 原始数据格式: 首先需要将后端返回的数据转为前端定义的格式,方便使用: [{&qu…

jsqlparse工具拦截sql处理和拓展

前置知识 访问者模式 (Visitor Pattern)是一种行为设计模式,它允许你定义在不改变被访问元素的类的前提下,扩展其功能。通过将操作(操作或算法)从对象结构中提取出来,可以在不修改这些对象的前…

机器学习与模式识别_清华大学出版社

contents 前言第1章 绪论1.1 引言1.2 基本术语1.3 假设空间1.4 归纳偏好1.5 发展历程1.6 应用现状 第2章 模型评估与选择2.1 经验误差与过拟合2.2 评估方法2.3 性能度量2.3.1 回归任务2.3.2 分类任务 2.4 比较检验2.5 偏差与方差2.5.1 偏差-方差分解2.5.2 偏差-方差窘境 第3章 …

航空数据管控系统-②项目分析与设计:任务2:使用Git或SVN管理项目(可选任务,只介绍Git安装)

任务描述 1、安装Git 2、注册GitHub 3、配置本地库 4、配置远程库 5、使用Git管理项目 任务指导 分为以下几个部分完成: 学会Git的安装,帐号注册本地存储库的管理自己创建一个项目,项目名称为自己的名字,上传到代码仓库&#xff…

符号速率、调制方式、码率、传输速率

符号速率、调制方式、码率(比特率)和传输速率在通信系统中是相互关联且重要的概念,它们之间的关系可以归纳如下: 一、定义 符号速率(Symbol Rate): 也称波特率(Baud Rate&#xff…

一文搞懂到底什么是 AQS

日常开发中,我们经常使用锁或者其他同步器来控制并发,那么它们的基础框架是什么呢?如何实现的同步功能呢?本文将详细讲解构建锁和同步器的基础框架--AQS,并根据源码分析其原理。 一、什么是 AQS? (一) AQS…

Element中的日期时间选择器DateTimePicker和级联选择器Cascader

简述:在Element UI框架中,Cascader(级联选择器)和DateTimePicker(日期时间选择器)是两个非常实用且常用的组件,它们分别用于日期选择和多层级选择,提供了丰富的交互体验和便捷的数据…

CD4017 – 带解码输出的十进制计数器

CD4017 IC 是一个十进制计数器,它有 10 个输出,分别代表 0 到 9 的数字。计数器在(14号引脚)每个时钟脉冲上升时增加 1。计数器达到 9 后,它会在下一个时钟脉冲时从 0 重新开始。 引脚名称管脚 #类型描述VD…

arthas命令使用

dashboard(线程、内存等环境概览) jvm(JVM相关信息概览) 1、RUNTIME(系统运行环境JVM相关信息,运行时长等) 2、CLASS-LOADING(类加载信息) 3、 COMPILATION(编译信息) 4…

Qt 网络编程实战

一.获取主机的网络信息 需要添加network模块 QT core gui network主要涉及的类分析 QHostInfo类 QHostInfo::localHostName() 获取本地的主机名QHostInfo::fromName(const QString &) 获取指定主机的主机信息 addresses接口 QNetworkInterface类 QNetworkInterfac…

Python——面向对象编程(类和对象)2

目录 私有属性和私有方法 01.应用场景及定义方式 02.伪私有属性和私有方法 继承 1.1继承的概念、语法和特点 1.继承的语法: 2.专业术语: 3.继承的传递性 1.2方法的重写 1.覆盖父类的方法 2.对父类方法进行扩展 关于super 1.3 父类的私有属性和…

机械拆装-基于Unity-装配功能的实现

目录 1. 装配场景的相机控制 2. 鼠标拖拽和旋转功能的实现 2.1 鼠标拖拽 2.2 物体旋转 3. 零件与装配位置的对应关系 4. 轴向装配的准备位置 5. 装配顺序的实现 5.1 标签提示 5.2 定义一个变量记录步骤数值 1. 装配场景的相机控制 开始装配功能时,需要将相机调…

vector与list的简单介绍

1. 标准库中的vector类的介绍: vector是表示大小可以变化的数组的序列容器。 就像数组一样,vector对其元素使用连续的存储位置,这意味着也可以使用指向其元素的常规指针上的偏移量来访问其元素,并且与数组中的元素一样高效。但与数…

1975react社区问答管理系统开发mysql数据库web结构node.js编程计算机网页源码

一、源码特点 react 社区问答管理系统是一套完善的完整信息管理类型系统,结合react.js框架和node.js后端完成本系统,对理解react node编程开发语言有帮助系统采用node框架(前后端分离)),系统具有完整的源…

6种ETL计算引擎介绍

目录 一、ETL计算引擎定义 二、ETL计算引擎的功能和特性 三、6种ETL计算引擎 1、MapReduce 2、Tez 3、Spark 4、Flink 5、ClickHouse 6、Doris 一、ETL计算引擎定义 ETL(Extract, Transform, Load)计算引擎是用于执行ETL过程中数据转换阶段的关键组件之一…

mac如何压缩视频大小不改变画质,mac怎么压缩视频软件

在数字时代,视频已成为信息传递和娱乐消遣的重要媒介。然而,视频带来的愉悦体验背后,是日益增长的存储和分享压力。大视频文件不仅占用大量存储空间,上传和下载也变得异常缓慢。那么,如何才能有效压缩视频,…

ERROR: No matching distribution found for numpy

1.原因: 出现这两行英文是因为原先输入pip install numpy的方式不安全,不被信任所以无法下载。 2.解决方法: 改成以下命令执行: pip install numpy -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun…