MySQL缓冲池详解

Buffer Pool

本文参考开源项目:小林coding在线文档;

01-缓冲池概述

​ 在MySQL查询数据的时候,是通过存储引擎去磁盘做IO来获取数据库中的数据,这样每次查询一条数据都要去做一次或者多次磁盘的IO,无疑是非常慢的。而缓冲池就能非常好的解决这个问题。

当数据从磁盘中取出后,缓存内存中,下次查询同样的数据的时候,直接从内存中读取。为此,Innodb 存储引擎设计了一个缓冲池(Buffer Pool),来提高数据库的读写性能

有了缓冲池后:

  • 当读取数据时,如果数据存在于 Buffer Pool 中,客户端就会直接读取 Buffer Pool 中的数据,否则再去磁盘中读取。
  • 当修改数据时,首先是修改 Buffer Pool 中数据所在的页,然后将其页设置为脏页,最后由后台线程将脏页写入到磁盘。

在这里插入图片描述

02-缓冲池存储的内容

2.1-数据页在缓冲池中的存储

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

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

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

在这里插入图片描述

接下来我们讨论一下数据在缓冲池中是如何存储以及处理的:

1、既然我们要在缓冲池里存储数据页,那么数据页是怎样存储的呢?

​ 在MySQL启动的时候,会申请一段连续的内存空间,缓冲池里有着许多的缓存页,而每个缓存页有唯一对应一个控制块,实际的存储情况如下图所示:

在这里插入图片描述

2、为什么上图会有空白的地方?

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

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

2.2-缓冲池数据页的管理

2.2.1-Free链表

​ 当我们的MySQL运行了一段时间后,缓冲池中的页有空闲的也有被使用的,当读取缓冲池中没有的数据时,我们要从磁盘去读取,磁盘读取之后,需要存到缓冲池。

​ 但是此时我们读取到的数据应该放到哪个页中呢?当然是得放在空闲页中,那么我们应该如何找到空闲页呢,在MySQL缓冲池中,MySQL建立了一个Free链表,用来管理空闲的缓存页,当我们从磁盘新读到的数据,Free链表如图所示。

在这里插入图片描述

2.2.2-Flush链表

​ 当对MySQL的数据进行修改操作后,并不需要每次都将缓冲池中的页写入磁盘,因为这样效率是比较低的,当缓存页中的数据发生改变后,MySQL会将该页标识为脏页

​ 与空闲页相同,MySQL也有一个Flush链表,记录了缓冲池中所有的脏页,Flush链表中的元素都是脏页,这样将脏页写入磁盘中就不用再去遍历所有的缓存页查看是否是脏页了,直接将Flush链表中的所有对应的缓存页写入磁盘就行,Flush链表如下图所示:

在这里插入图片描述

2.2.4-LRU链表

​ MySQL为了提高缓冲池的命中率,对于一些频繁使用的数据需要将其留在缓冲池中,在MySQL中使用了LRU(最近最少使用算法),该算法会淘汰最近最少使用的页,在MySQL缓冲池中有一个LRU链表。

下图我们可以看到LRU链表有一个头指针和尾指针,一个简单的LRU算法的实现是这样的:

  • 当访问的页在 Buffer Pool 里,就直接把该页对应的 LRU 链表节点移动到链表的头部
  • 当访问的页不在Buffer Pool里时,需要先把页放在LRU链表的头部,还要将尾部的页淘汰掉

假设现在有一个LRU链表,长度为5,目前有1、2、3、4、5五个页位于LRU链表中,也就是说有五个位于缓冲池中,如图所示:

在这里插入图片描述

现在假设我们要访问页3,那么我们就会将页3移动到head的位置,如图下图所示:

在这里插入图片描述

现在假设我们要访问页8,但是页8位于磁盘中,所以此时我们要将页8加入到LRU链表中,因此我们会淘汰掉末尾的页5,如图所示:

在这里插入图片描述

2.2.5-预读失效

对于如上所示的LRU算法会有一个预读失效的问题,我们先来解释一下预读失效是什么。

在MySQL加载数据页到缓冲池中时,由于空间局部性【访问谋个数据后,接下来很可能会访问其相邻的数据】,加载磁盘中的页到内存时,会将相邻存储的页也加载到内存中,但是如果提前加载的数据接下来不会被访问,这个就叫做预读失效

预读失效导致的问题:

​ 如果使用上述的LRU算法,那么就会导致一个问题,由于预读失效,加载了不会被访问的页放在了缓冲池中,由于加载了新的页,所以会要淘汰缓冲池中存在的页,那么就会导致缓冲池中可能会被频繁访问的页被淘汰了出去,这样就会降低缓冲池命中率。

​ MySQL对于预读问题的解决方案是将LRU链表划分成young区域和old区域,young区在LRU链表的前半部分,而old区域在LRU链表的后半部分。如下图所示。

在这里插入图片描述

​ 关于young区域和old区域在LRU链表中的占比也可以通过参数设置,可以通过innodb_old_blocks_pct参数进行设置,默认值是37,代表在缓冲池中,young区域和old区域占比是63:37。

解决预读失效产生的问题,当发生预读的时候,MySQL不会将预读的数据放到young区域,而是放在old区域的head部分,只有当预读的数据被访问的时候,才会被放在young区域的head部分,

2.2.6-Buffer Pool污染

​ 上述使用LRU链表分young区和old区虽然能够解决预读失效导致的命中率下降问题,但是还存在Buffer Pool污染问题,我们先来介绍一下什么是buffer pool污染。

当一个SQL语句扫描了大量的数据的时候,在缓冲池空间比较有限的情况下,可能会将缓冲池中所有的热点数据都替换出去,等这些热点数据被再次访问的时候,由于缓存没有命中,就会产生大量磁盘IO,导致MySQL性能急剧下降,这种情况就叫Buffer Pool污染。

​ 关于Buffer Pool污染的问题,MySQL是这样处理的,进入young区域条件增加了一个停留在old区域的时间判断。具体的处理是这样的,当访问第一次old区域的某个缓存页时,在其对应的控制块中记录当前访问的时间:

  • 如果后续访问时间与第一次访问的时间在某个时间段内,那么这个缓存页不会从old区移到young区的头部
  • 如果后续访问时间与第一次访问的时间不在某个时间段内,那么就会将这个缓存页从old区域移动到young区的头部

这个时间间隔可以通过innodb_old_blocks_time控制,默认的时间是1000ms。

​ 如果在默认的情况下,只有同时满足一次以上的访问以及在old区停留超过1s两个条件,才会被从old区移动到young区的头部,这样就解决了Buffer Pool污染的问题。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

mxnet系统架构

mxnet系统架构 MXNet 是一个高性能、灵活的深度学习框架,最早由李沐(Mu Li)等人开发,并且得到了 Amazon 的支持。它支持多种语言(包括 Python、Scala、C、R、Julia、Perl 等),并以其灵活的编程…

EfficientNet V1 V2

v1 论文地址:https://arxiv.org/abs/1905.11946 网络深度、宽度和图像分辨率,进行了栅格搜索(Grid Search),找到了最优的几种搭配。 v2 论文地址:https://arxiv.org/abs/2104.00298 Fused-MBConv 到搜…

SpringBoot教程(三十) | SpringBoot集成Shiro权限框架(shiro-spring 方式)

SpringBoot教程(三十) | SpringBoot集成Shiro权限框架(shiro-spring方式) 一、 什么是Shiro二、Shiro 组件核心组件其他组件 三、流程说明shiro的运行流程 四、SpringBoot 集成 Shiro1. 添加 Shiro 相关 maven2. 添加 其他 maven3…

6种解决msvcp140_ATOMIC_WAIT.dll丢失的方法分享

日常生活工作中,电脑已经成为我们生活和工作中不可或缺的工具。然而,在使用过程中,我们也会遇到各种问题,其中之一就是电脑中的msvcp140_ATOMIC_WAIT.dll文件丢失。这个问题可能会导致电脑运行不稳定,甚至无法正常启动…

7-51 7-52 两个有序链表序列并集 和 交集

7-51代码&#xff1a;&#xff08;map) #include<iostream> #include<map> using namespace std; map<int,int>mp; int cnt,cnttp; void scan(){while(1){int x; scanf("%d",&x);if(x-1) break;mp[x];cnt;} } int main(){scan();scan();if(!…

基于波特图的控制系统设计算法

波特图&#xff08;Bode Plot&#xff09;是一种用于描述线性控制系统频率响应的图形表示方法&#xff0c;通常用于分析和设计控制系统。它以控制系统的传递函数&#xff08;或频域传递函数&#xff09;为基础&#xff0c;将系统的幅频特性&#xff08;振幅-频率响应&#xff0…

【MySQL】 索引

MySQL与磁盘存储 MySQL就是提供数据存储服务的&#xff0c;而最终存储的位置就是磁盘&#xff0c;但是磁盘存储速度慢&#xff0c;所以MySQL如何与磁盘交互&#xff0c;提高数据存储效率&#xff0c;即是MySQL和磁盘交互。 磁盘基础知识回顾 物理结构 磁道&#xff1a;磁盘是…

ARM 栈和函数调用

阅读本文前&#xff0c;可以先阅读下述文档&#xff0c;对函数栈、栈帧等的概念会有所了解&#xff0c;会对本文章的理解大有益处 X86_64 栈和函数调用 1、调试环境 Ubuntu&#xff1a; liangjieliangjie-virtual-machine:~/Desktop$ cat /proc/version Linux version 6.5.0…

c++9月20日

1.思维导图 2.顺序表 头文件 #ifndef RECTANGLE_H #define RECTANGLE_H#include <iostream>using namespace std;using datatype int ;//类型重定义class Seqlist { private://私有权限datatype *ptr; //指向堆区申请空间的起始地址int size;//堆区空间的长度int len …

leetcode第十二题:整数转罗马数字

七个不同的符号代表罗马数字&#xff0c;其值如下&#xff1a; 符号值I1V5X10L50C100D500M1000 罗马数字是通过添加从最高到最低的小数位值的转换而形成的。将小数位值转换为罗马数字有以下规则&#xff1a; 如果该值不是以 4 或 9 开头&#xff0c;请选择可以从输入中减去的…

利用LRZ压缩与Base64编码实现高效文件上传

引言 在当今互联网时代&#xff0c;文件上传已成为众多在线服务不可或缺的一部分&#xff0c;尤其是在社交媒体平台上的照片分享和云存储服务中的文档管理等场景&#xff0c;高效且安全的文件上传机制对于保障用户体验至关重要。 为此&#xff0c;本文将介绍一种结合了LRZ压缩…

使用vite+react+ts+Ant Design开发后台管理项目(三)

前言 本文将引导开发者从零基础开始&#xff0c;运用、react、react-router、react-redux、Ant Design、less、tailwindcss、axios等前沿技术栈&#xff0c;构建一个高效、响应式的后台管理系统。通过详细的步骤和实践指导&#xff0c;文章旨在为开发者揭示如何利用这些技术工具…

VSCode环境下连接 MySQL 8.0 数据库 (C++)

前言 时隔了不知道多久&#xff0c;笔者需要在Windows环境下通过VSCode重新搭建一个简单的数据库连接的Cpp工程。由于VSCode和MySQL的版本和之前连通时发生了一些变化&#xff0c;无需用MySQL Connector&#xff0c;环境配置的细节和之前也不尽相同&#xff0c;因此笔者找了一…

简单有效关于msvcp140.dll丢失的解决方法,msvcp140.dll修复的方法原理及步骤

这篇文章将和大家分享几种msvcp140.dll丢失的解决方法&#xff0c;分析解决方法为什么能够通过这种方法进行修复成功&#xff0c;有效的将丢失的msvcp140.dll文件进行修复完成。 msvcp140.dll丢失&#xff1f;简单有效的解决途径 一、重新安装相关软件 原理 许多应用程序在安…

掌握Android开发新趋势:Jetpack与现代架构技术全解析

随着Android开发技术的不断进步&#xff0c;Jetpack和现代架构技术已成为构建高效、可维护应用的关键。本文将为您介绍一套全面的学习资料&#xff0c;包括大纲、PDF文档、源代码以及学习视频&#xff0c;帮助您深入理解Jetpack核心库、架构组件以及现代开发工具。 内容&#…

【C++】—— string模拟实现

前言&#xff1a; 学习了string的使用&#xff0c;总感觉了解不是很深厚&#xff1b;自己模拟实现string类来帮助自己理解。 这里只是实现了一部分内容&#xff08;并没有实现完整的string类&#xff09;。 先来实现string类里面的成员变量&#xff1a; #include<iostream…

草莓团队创造了o1 - Building OpenAI o1 (Extended Cut) 观后笔记

美妙的事物往往需要世界去创造&#xff0c;商业希望大模型越来越快给出回答。或许花费几个月几年的时间持续思考&#xff0c;大模型能够解决更复杂的问题&#xff0c;而不只是回答42 刚发现凌晨OpenAI发布了一个22多分钟的采访&#xff0c;将构建出O1的整个团队拉到一个小屋子&…

让Tkinter更美观:教你同步Tkinter窗口与弹窗图标(Tkinter同步主窗口与Messagebox的图标)

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 文章内容 📒📝 步骤1:主窗口图标📝 步骤2:messagebox 图标📝 示例代码📝 实现原理与代码解释⚓️ 相关链接 ⚓️📖 介绍 📖 你有没有注意到,在开发软件图形界面时,会需要弹出一些提示框,而这些提示框的图标总…

695. 岛屿的最大面积

思路&#xff1a; 只有当前是陆地&#xff0c;才会构成岛屿 当前是陆地&#xff0c;进入回溯 往当前的上、下、左、右位置分别找陆地位置&#xff0c;为陆地 1>标记为2:代表已经遍历过的陆地 2>记录当前方向的陆地总数 以当前陆地组成的岛屿面积当前陆地面积向上的…

11----mtk芯片专用解锁工具 解除FRP 很小的工具 去除屏幕锁 免授权等等 工具预览与步骤解析

机型的FRP锁是谷歌账号锁。工具是mtk芯片使用 。可以去除当前机型的FRP和米账号重置。操作非常简单。但前提是联机驱动要装好。任何的工具联机驱动是关键。 工具功能选项 ★★★★★工具开发者说明功能与选项操作与资源下载 ★★★★★具体工具操作使用指南 工具联机界面与…