Mysql-缓冲池 buffer pool

缓冲池 buffer pool

innodb中的数据是以【页】的形式存储在磁盘上的表空间内,但是【磁盘的速度】和【内存】相比简直不值一提,而【内存的速度】和【cpu的速度】同样不可同日而语,对于数据库而言,I/O成本永远是不可忽略的一项成本,我们不妨思考下面的小问题:

小问题:一个全表扫描会产生有多少次磁盘I/O?

select * from user where id between 10 and 1000;
  • 访问id为1的数据,需要访问当前表空间的第一行数据,一次I/O
  • 访问id为2的数据,需要访问当前表空间的第二行数据,两次I/O
  • 访问id为3的数据,需要访问当前表空间的第三行数据,三次I/O…

我们发现id为1,2,3…的数据都在同一个【数据页】,这会导致一个严重的问题,一次简单的查询,会访问【同一个页很多次】,可能产生很几百次I/O操作。所以为了解决快如闪电的【cpu】,和慢如蜗牛的【磁盘】之间的矛盾,innodb设计了buffer pool,我们直接读取数据所在页和相邻的页到缓存,有了缓存之后我们的执行过程如下:

  • 访问id为1的数据,需要访问当前表空间的第一行数据,缓存当前页,一次I/O
  • 访问id为2的数据,需要访问当前表空间的第二行数据,从缓存获取,无需I/O
  • 访问id为3的数据,需要访问当前表空间的第三行数据,从缓存获取,无需I/O…

Innodb引擎会在mysql启动的时候,向操作系统申请一块连续的空间当做buffer pool,空间的大小由变量innodb_buffer_pool_size确定,我这台电脑他使用了8G,你的可能是128M。

在这里插入图片描述

一、缓冲池的内部结构

整个buffer pool是由【缓冲页和控制块】组成的:

  • 缓冲页:buffer pool中存放的【数据页】我们称之为【缓冲页】,和磁盘上的数据页是一一对应的,都是16KB,缓冲页的数据,是从磁盘上加载到buffer pool当中的一个完整页。
  • 控制块:他是缓冲页【描述信息】,这一块区域保存的是数据页所属的表空间号,数据页编号,数据页地址,以及一些链表相关的节点信息等,每个控制块大小是缓存页的5%左右,大约是800个字节。

其内部结构如下,buffer pool的前一部分存储【控制块】,后一部分存储【缓冲页】,如果中间有未被利用的空间,就叫他【内存碎片】吧:

在这里插入图片描述

buffer pool的初始化:

​ 数据库会在启动的时候,按照配置中的Buffer Pool大小,去向操作系统申请一块内存,作为Buffer Pool的内存区域,然后会按照默认的缓存页的的大小【16KB】以及对应的【800个字节左右】的【控制块】的大小,在Buffer Pool中划分出一个一个的缓存页和一个一个与其对应的描述数据(控制块)。此时的buffer pool像一个干净的本子,没有书写任何内容

二、free链

​ 刚初始化的buffer pool,内存中都是【空白的缓冲页】,但是随着时间的推移,程序在执行过程中会不断的有新的页被缓存起来,那怎么来判断哪些缓冲页是【闲置状态】,可以被使用呢,此时就需要【控制块来进行标记和管理】了。

​ innodb在设计之初,会将所有【空闲的缓冲页】所对应的【控制块】作为一个个的节点,形成一个链表,这个链表就是free链,这个链表就是一串未被使用的控制块,翻译过来就是空闲链表,如下图:

在这里插入图片描述

由上图可知,free链表是一个双向链表,链表上除了控制块以外,还有一个基础节点,存储了free链有多少个描述信息块,也就是有多少个空闲的缓存页,以及指向链表头尾的指针。

当我们加载数据的时候,会从free链中找到空闲的缓存页,把数据页的【表空间号和数据页】号写入【控制块】。

加载数据到缓存页后,会把缓存页对应的控制块从free链表中移除。

(1)、怎么知道数据页是否被缓存?

​ 我们已经有了free链表用来【保存空闲的页】,但是,当下一次访问时,要如何知道当前要访问的页是不是已经被缓存了,最直观的思路就是将buffer poll里的缓存数据【全部遍历一遍】。

​ 显然,这样做并不合理,本来设计buffer pool是为了提升效率,如果有人将buffer pool配置的很大,比如32个G,那扫描这一片区域的功夫都可以喝一杯茶了,反而成了累赘。

事实上,我们使用的hash算法,使用【表空间号+页号】进行hash就可以确定一个唯一的页

那么我们能不能设计一个hash表,使用【表空间号+页】号当做key,使用【控制块地址】做value,每次查询的时候只需要通过key进行查找即可,大家都知道hash的时间复杂度是O(1),这样就能迅速定位缓存的页。(和hashmap很像)

结合我们的free链表,查询/缓存一个页的流程大致如下:

在这里插入图片描述

三、flush链表

(1)、脏页

​ 在sql的执行过程中,无论是增删改查,都是优先在buffer pool中进行的,这样可以极大的保证执行效率。

但是同样会有一个问题,假如我们对缓存页的某些数据进行了修改(执行了一条update语句),就会导致buffer pool中的缓冲页和磁盘的数据页【数据不一致】,那么此时的缓冲页就称之为【脏页】。当然,这也就说明了,脏页的数据是要刷到磁盘上的

(2)、链表结构

在这里插入图片描述

  • flush链表同样是一个双向链表,链表结点是被【修改过的缓存页】的控制块。
  • 和free链表一样,flush链表也有一个基础结点,链接首尾结点,并存储了有多少个控制块。

(3)、刷盘时机

后台会有专门的线程每隔一段时间就把flush链表中的脏页刷入磁盘中,刷新的速率取决与当前系统是否繁忙。

在这样的机制下,万一系统奔溃,是会产生数据不一致的问题的,没有刷入磁盘的数据就会丢失,而mysql通过日志系统解决了这个问题。

四、LRU链表

(1)、概述

内存是有限的,buffer pool更是有限的;缓存只是数据的中转站,当我们的数据量很大以后,buffer pool其实是仅仅能容纳很少一部分数据,所以buffer pool的容量很有可能被使用殆尽,如果此时我们还想继续缓存数据页那该怎么办?

合理的做法就是,当需要更多的空间缓存【新的数据页】的时候,我们将最近使用最少的【缓冲页淘汰掉】就可以了,这就是典型的LRU(最近最少使用)算法,对于innodb而言,是通过【LRU链表】来完成此功能的,他的结构和free链表、flush链表基本相同,只是负责的功能不同而已。

于是,一个简单的思路诞生了,当客户端访问一条数据时,会加载对应的数据页到buffer pool,并会将缓冲页对应的控制块放置到【LRU链表的首位】。一旦buffer pool被占满,则从链表的末端开始淘汰数据,这是最简单的实现。

(2)、优化

但是,实际的在使用场景中,我们需要对原有的LRU链表进行优化,因为他在一下场景可能会出现一些问题:

  • 数据页预读:我们在讲多线程的时候是讲过【预读性原理】(当一个应用在访问一个数据时,很有可能会继续访问和他相邻的数据),cpu的高级缓冲区读取主存的数据也不是一个字节一个字节的读取,而是一下子会读取一个【缓存行】。同理,innodb从磁盘读取数据,也不一定是一页页读取,当mysql读取当前需要的页时,如果觉得后续操作会使用【附近的页】,就会将他们一起缓存到buffer pool,这样的作用是为了提升效率。但是,这也会导致大量的使用频率并不高的数据放置在LRU链表头部,反而将一些真正的【热点数据】淘汰
  • 全表扫描:一条【select * from user】 语句,会直接将一张表的全表数据缓存,并全部放在LRU链表头部,一样会淘汰很多热点数据

所以,innodb对该链表进行了优化,将【LRU链表】分成了两个区域,分为【热数据区】和【冷数据区】,默认情况下冷数据区占了总链表的37%,机构如下:

在这里插入图片描述

一个select语句可能会多次访问一个页,因为你有【很多数据是保存在同一个页内】的。对于一个全表扫描的语句,每访问一条数据,就会访问一次相关的页,所以缓存确实能极大的提升效率:

  • 对于预读的数据页,会在第一次访问时放入old区域,如果在sql执行的过程中访问相邻数据时,再次访问访问到该数据页,则把他加入如热数据区

  • 【大表的全表扫描】是个使用频率很低的操作(小表怎么操作都无所谓),但是如果按照上边的操作,首先全表数据会被放在【old区】,全表扫描必然会因为访问相邻数据而产生第二次、第三次、甚至数百次的访问,也就以为着这些页面会被全部放在young区。为了解决这个问题,INnodb提供了这样一个参数【innodb_old_blocks_time】,默认是1s,他的执行流程大致如下:

    1、页被首次访问时会记录访问的时间戳。

    2、以后访问都和首次访问的时间进行对比,如果时间大于1s,就讲当前页放入yong区。

    3、一个sql的扫描一个页的时间,哪怕在慢也不会低于1s,这样就解决了一个全表扫秒而导致全表成为热点数据的问题。

tips:也就意味着,热点数据要求首次访问时间和最后一次访问时间的时间差不能低于1s。

在这里插入图片描述

tips:使用以下的语句,可以查看innodb当前的状态:

show engine innodb status
Total large memory allocated 8585216                  # 为innodb 分配的总内存数(byte)
Dictionary memory allocated 446370                    #为innodb数据字典分配的内存数(byte)
Buffer pool size   512                                #innodb_buffer_pool的大小(page)
Free buffers       101                                #innodb_buffer_pool lru列表中的空闲页面数量
Database pages     277                                #innodb_buffer_pool lru列表中的非空闲页面数
Old database pages 0                                  #innodb_buffer_pool old子列表的页面数量
Modified db pages  273                                #innodb_buffer_pool 中脏页的数量
Pending reads      1                                  #挂起读的数量
Pending writes: LRU 0, flush list 0, single page 0    #挂起写的数量
Pages made young 0, not young 0
0.00 youngs/s, 0.00 non-youngs/s
Pages read 8002054, created 766955, written 4652116
0.00 reads/s, 0.00 creates/s, 0.00 writes/s
Buffer pool hit rate 993 / 1000, young-making rate 0 / 1000 not 0 / 1000
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 277, unzip_LRU len: 0
I/O sum[22009]:cur[1940]unzip sum[0]:cur[0]

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于Elman神经网络预测计费系统的输出(Matlab代码实现)

目录 💥1 概述 📚2 运行结果 🎉3 参考文献 👨‍💻4 Matlab代码 💥1 概述 简单循环网络(simple recurrent networks,简称SRN)又称为Elman network,是由Jeff…

什么是AI文章生成器-AI文章生成器批量生成文章

AI文章生成器有哪些 目前市面上存在一些可以生成文章的 AI 文章生成器,以下是其中几种常见的: OpenAI GPT-3: OpenAI GPT-3 是目前最先进、最著名的 AI 文章生成器之一,它可以生成各种类型的文章,例如新闻报道、科学报…

我的Macbook pro使用体验

刚拿到Mac那一刻,第一眼很惊艳,不经眼前一亮,心想:这是一件艺术品,太好看了吧 而后再体验全新的Macos 系统,身为多年的win用户说实话一时间还是难以接受 1.从未见过的访达,不习惯的右键 2. …

[论文解析] Cones: Concept Neurons in Diffusion Models for Customized Generation

论文连接:https://readpaper.com/pdf-annotate/note?pdfId4731757617890738177&noteId1715361536274443520 源码链接: https://github.com/Johanan528/Cones 文章目录OverviewWhat problem is addressed in the paper?Is it a new problem? If so…

PMP一般要提前多久备考?

PMP很迷,有只备考了一周过的,也有备考几个月过的。保险起见,预留两个月比较靠谱,尤其现在是新考纲,PMP新版大纲加入了 ACP 敏捷管理的内容,而且还不少,敏捷混合题型占到了 50%,前不久…

AcWing3662. 最大上升子序列和(线性DP + 树状数组优化 + 离散化处理)

AcWing3662. 最大上升子序列和(线性DP 树状数组优化 离散化处理)一、问题二、分析1、DP过程(1)状态表示(2)状态转移2、数据结构优化(1)树状数组维护最值(2)…

K8s 弃用 Docker!一文介绍 containerd ctr、crictl 使用

containerd 是一个高级容器运行时,又名 容器管理器。简单来说,它是一个守护进程,在单个主机上管理完整的容器生命周期:创建、启动、停止容器、拉取和存储镜像、配置挂载、网络等。 containerd 旨在轻松嵌入到更大的系统中。Docke…

【ASPLOS 2023】图神经网络统一图算子抽象uGrapher,大幅提高计算性能

作者:周杨杰、沈雯婷 开篇 近日,阿里云机器学习平台PAI和上海交通大学冷静文老师团队合作的论文《图神经网络统一图算子抽象uGrapher》被ASPLOS 2023录取。 为了解决当前图神经网络中框架中不同的图算子在不同图数据上静态kernel的性能问题&#xff0…

【前沿技术】文心一言 PK Chat Gpt

目录 写在前面 一、文心一言 二、Chat GPT 三、对比 四、总结 写在前面 随着人工智能技术的不断发展和普及,越来越多的智能应用走入了人们的日常生活,如智能语音助手、智能客服、机器翻译等等。在这些应用中,自然语言生成(…

看完不再愁 | 图解TCP 重传、滑动窗口、流量控制、拥塞控制

目录 前言 正文 🌲 重传机制 1. 超时重传 2. 快速重传 3. SACK 方法 4. Duplicate SACK 🌲 滑动窗口 🌳 流量控制 🌳 拥塞控制 1. 慢启动 2. 拥塞避免算法 3. 拥塞发生 4. 快速恢复 前言 前面我们讲到「硬不硬你说…

Android开发一直在用大公司的开源库,可参考~

一、阿里巴巴 (一)UI有关 1. 多页面切换场景统一解决方案 UltraViewPager UltraViewPager 是阿里开源的一个封装多种特性的 ViewPager ,主要是为多页面切换场景提供统一解决方案。 主要功能: 1. 支持横向滑动/纵向滑动2. 支持一屏…

求红白黑球的个数-课后程序(JavaScript前端开发案例教程-黑马程序员编著-第2章-课后作业)

【案例2-11】求红白黑球的个数 一、案例描述 考核知识点 for循环语句、if判断语句 练习目标 掌握for循环应用。掌握if判断语句应用 需求分析 用js编程 已知:红白球共25个,白黑球共31个,红黑球共28个,求三种球各有多少&#xff…

基于STM32 SG90 9g舵机控制

文章目录一、什么是舵机?二、工作原理三、利用PWM控制四、stm32舵机控制一、什么是舵机? 产品参数 名称:9克舵机180度 尺寸:23mm X 12.2mm X 29mm 重量:9克 扭矩:1.5kg/cm 工作电压:4.2 - 6V 温…

Java大数字运算(BigInteger类和BigDecimal类)

在 Java 中提供了用于大数字运算的类,即 java.math.BigInteger 类和 java.math.BigDecimal 类。这两个类用于高精度计算,其中 BigInteger 类是针对整型大数字的处理类,而 BigDecimal 类是针对大小数的处理类。 BigInteger 类 如果要存储比 …

一本通 3.3.1 树与二叉树

树与二叉树的基本知识 1336&#xff1a;【例3-1】找树根和孩子 【题目描述】 给定一棵树&#xff0c;输出树的根root&#xff0c;孩子最多的结点max以及他的孩子。 【题目分析】 【代码实现】 #include<bits/stdc.h> using namespace std; int father[201], sum[101]…

8.OSP的GR(Graceful Restart,平滑重启)实验

一、GR(Graceful Restart,平滑重启) 技术介绍 GR(Graceful Restart,平滑重启)技术保证了设备在重启过程中转发层面能够继续指导数据的转发,同时控制层面邻居关系的重建以及路由计算等动作不会影响转发层面的功能,从而避免了路由振荡引发的业务中断,保证了关键业务的数…

Java_Spring:5. 基于注解的 IOC 配置

目录 1 环境搭建 1.1 第一步&#xff1a;拷贝必备 jar 包到工程的 lib 目录。 1.2 第二步&#xff1a;使用Component 注解配置管理的资源 1.3 第三步&#xff1a;创建 spring 的 xml 配置文件并开启对注解的支持 2 常用注解 2.1 用于创建对象的注解 2.1.1 Component 2.1…

【MySQL高级篇】第09章_性能分析工具的使用

第09章_性能分析工具的使用 在数据库调优中&#xff0c;我们的目标是 响应时间更快, 吞吐量更大 。利用宏观的监控工具和微观的日志分析可以帮我们快速找到调优的思路和方式。 1. 数据库服务器的优化步骤 当我们遇到数据库调优问题的时候&#xff0c;该如何思考呢&#xff1…

在vue项目中使用echarts(echarts不显示,echarts使用详细)

简述&#xff1a;我们在写大屏项目和vue项目时经常会用到echarts&#xff0c;用于数据统计和可视化&#xff0c;它是一款基于JavaScript的数据可视化图表库&#xff0c;提供直观&#xff0c;生动&#xff0c;可交互&#xff0c;可个性化定制的数据可视化图表&#xff0c;下面分…

【IAR工程】STM8S208RB基于ST标准库蜂鸣器(BEEP)驱动

【IAR工程】STM8S208RB基于ST标准库蜂鸣器(BEEP)驱动&#x1f33e;寄存器版本《STM8S系列基于IAR开发&#xff1a;蜂鸣器&#xff08;BEEP&#xff09;驱动功能模块示例》&#x1f33f;相关篇《【IAR工程】STM8S208RB基于ST标准库下GPIO点灯示例》&#x1f33f;《【IAR工程】ST…