MySQL原理(七):内存管理和磁盘管理

news2024/9/22 19:44:29

前言

上一篇介绍了 MySQL 的日志,这一篇将介绍内存管理和磁盘管理相关的内容。

内存管理

MySQL 的数据都是存在磁盘中的,我们要更新一条记录的时候,得先要从磁盘读取该记录,然后在内存中修改这条记录。修改完这条记录后会缓存起来,下次有查询语句命中了这条记录,就可以直接读取缓存中的记录,不需要再从磁盘获取数据了。

Buffer Pool

MySQL 对数据的增删改查都是在内存中完成的,即在 Buffer Pool 中完成的。

缓存池是 Innodb 存储引擎设计并实现的,是 InnoDB 中的一块内存区域,默认大小是 128M。MySQL 启动后会初始化 Buffer Pool。

  • 当读取数据时,如果数据存在于 Buffer Pool 中,客户端就会直接读取 Buffer Pool 中的数据,否则再去磁盘中读取。
  • 当修改数据时,如果数据存在于 Buffer Pool 中,那直接修改 Buffer Pool 中数据所在的页,然后将其页设置为脏页(该页的内存数据和磁盘上的数据已经不一致),为了减少磁盘I/O,不会立即将脏页写入磁盘,后续由后台线程选择一个合适的时机将脏页写入到磁盘。

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

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

在这里插入图片描述

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

控制块也是占有内存空间的,它是放在 Buffer Pool 的最前面,接着才是缓存页,控制块和缓存页之间灰色部分称为碎片空间。

在这里插入图片描述

为了能够快速找到空闲的缓存页,可以使用链表结构,将空闲缓存页的「控制块」作为链表的节点,这个链表称为 Free 链表(空闲链表)。

在这里插入图片描述

为了能快速知道哪些缓存页是脏的,于是就设计出 Flush 链表,它跟 Free 链表类似的,链表的节点也是控制块,区别在于 Flush 链表的元素都是脏页。

LRU

为了提高缓存命中率,MySQL 改进了 LRU(Least Recently Used) 算法,将 LRU 划分了 2 个区域:old 区域 和 young 区域。young 区域在 LRU 链表的前半部分,old 区域则是在后半部分。

old 区域占整个 LRU 链表长度的比例可以通过 innodb_old_blocks_pc 参数来设置,默认是 37,代表整个 LRU 链表中 young 区域与 old 区域比例是 63:37。

改进过后的 LRU 算法可以解决两个问题:预读失效和 Buffer Pool 污染。

预读失效

预读机制:程序是有空间局部性的,靠近当前被访问数据的数据,在未来很大概率会被访问到。所以,MySQL 在加载数据页时,会提前把它相邻的数据页一并加载进来,目的是为了减少磁盘 IO。

但是可能这些被提前加载进来的数据页,并没有被访问,相当于这个预读是白做了,这个就是预读失效

划分这两个区域后,预读的页就只需要加入到 old 区域的头部,当页被真正访问的时候,才将页插入 young 区域的头部。如果预读的页一直没有被访问,就会从 old 区域移除,这样就不会影响 young 区域中的热点数据。

Buffer Pool 污染

当某一个 SQL 语句扫描了大量的数据时,在 Buffer Pool 空间比较有限的情况下,可能会将 Buffer Pool 里的所有页都替换出去,导致大量热数据被淘汰了,等这些热数据又被再次访问的时候,由于缓存未命中,就会产生大量的磁盘 IO,MySQL 性能就会急剧下降,这个过程被称为 Buffer Pool 污染

Buffer Pool 污染并不只是查询语句查询出了大量的数据才出现的问题,即使查询出来的结果集很小,也会造成 Buffer Pool 污染。

比如,在一个数据量非常大的表,执行了这条语句:

select * from user where name like "%a%";

可能这个查询出来的结果就几条记录,但是由于这条语句会发生索引失效,所以这个查询过程是全表扫描的,接着会发生如下的过程:

  • 从磁盘读到的页加入到 LRU 链表的 old 区域头部;
  • 当从页里读取行记录时,也就是页被访问的时候,就要将该页放到 young 区域头部;
  • 接下来拿行记录的 name 字段和字符串 xiaolin 进行模糊匹配,如果符合条件,就加入到结果集里;
  • 如此往复,直到扫描完表中的所有记录。

为了解决这个问题,MySQL 对进入到 young 区域条件增加了一个停留在 old 区域的时间判断。只有在 old 区域停留时间超过一定时间,才会被插入到 young 区域头部。

另外,MySQL 针对 young 区域其实做了一个优化,为了防止 young 区域节点频繁移动到头部。young 区域前面 1/4 被访问不会移动到链表头部,只有后面的 3/4被访问了才会。

脏页刷盘

把脏数据刷回磁盘的技术又称 checkpoint 技术。

MySQL 的脏页落盘是由后台线程定期异步执行的。

  1. 当 redo log 满了的情况下,会主动触发脏页刷新到磁盘;
  2. Buffer Pool 空间不足时,需要将一部分数据页淘汰掉,如果淘汰的是脏页,需要先将脏页同步到磁盘;
  3. MySQL 认为空闲时,后台线程回定期将适量的脏页刷入到磁盘;即使非空闲时,也会见缝插针地刷盘;
  4. MySQL 正常关闭之前,会把所有的脏页刷入到磁盘;

在 MySQL 的使用过程中,可能会出现抖动(突然变得很慢,且 CPU 资源被大量占用),很大可能就是在刷盘,即情况 12。

change buffer

写缓存,change buffer 是 buffer pool 的一部分,当需要修改的数据页不在缓存池内时,会在 change buffer 中记录数据变更,等未来数据被读取时,再将数据 merge 到缓存池中。

在这里插入图片描述

在 MySQL5.5 之前,叫插入缓冲(insert buffer)只针对 insert 做了优化;现在对 delete 和 update 也有效,叫做写缓冲(change buffer)。

使用 change buffer 之前:

  1. 当需要更新的数据不在缓存池中时,从磁盘中读取数据页到 buffer pool;(一次磁盘随机读)
  2. 更新数据页;(一次写内存)
  3. 将数据页更新记录到 redo log,redo log 落盘。(一次磁盘顺序写)

使用 change buffer 之后:

  1. 当需要更新的数据不在缓存池中时,不需要从磁盘中读取数据页,而是在写缓存中记录这个变更操作;(一次写内存)
  2. 将数据页更新记录到 redo log,redo log 落盘;(一次磁盘顺序写)
  3. 当访问到该记录时,先从磁盘中读取数据页,再从写缓存中读取变更信息(如果有多个,则依次更新),最后更新到缓存池中,即 merge 操作。(一次磁盘随机读和一次写内存)
  4. 将缓存页和 change buffer 的更新记录到 redo log,redo log 落盘。(一次磁盘顺序写)

使用 change buffer,在更新频率高、查询频率低的场景下(且不是更新完马上查询),相当于可以减少一次磁盘随机读开销。(相当于只有步骤 12,和少量的步骤 34)

但是如果所有更新后面,都马上要对这个记录进行查询,那么 change buffer 反而会起到副作用。

merge 时机:

  • 数据页被读取
  • 后台线程认为数据库空闲时
  • 数据库正常关闭时

change buffer 只能用于非唯一普通索引页(non-unique secondary index page)。

因为如果索引设置了唯一属性,在进行修改操作时,InnoDB 必须进行唯一性检查。

比如,要插入(4,400)记录,要先判断表中是否已存 k=4 记录,而这必须要将数据页读入内存才能判断。如果都已经读入到内存,那直接更新内存会更快,就没必要使用 change buffer。

磁盘空间管理

空间碎片

MySQL 中有以下几种可能出现空间碎片的情况:

  • 修改行数据导致出现行间碎片;
  • 插入和修改数据可能导致页分裂,从而使数据页中有大量空余空间(数据页空余空间很难避免);

删除数据

delete

使用 delete 删除一条记录,只是在 B+ 树中将记录标记为删除状态(通过隐藏列中的 deleted_bit),删除后的记录不会消失,且可以被复用。

如果一个数据页上的所有记录都被删除了,那么整个数据页就可以被复用了。而且如果相邻的两个数据页的利用率都很小,系统就会把这两个页上的数据合并到其中一个页上,另外一个数据页就会被标记为可复用。

所以只是删除数据,占用的磁盘空间并不会减少,甚至可能增加。因为 delete 操作还会写入 redo log 和 undo log,从而占用更多的磁盘空间。

truncate

truncate 用于清空表内的数据,但是不会删除表本身。立刻释放磁盘空间。

drop

drop 用于删除整个表/库,包括表的结构、属性、索引等。立刻释放磁盘空间。

速度:drop>truncate>delete

空间回收

经过大量增删改的表,可能存在大量的空洞(数据页中可复用或未被使用的记录)。目前,能够回收表空间的办法仅有一个,就是重建表,手段包括但不限于 optimize,alter table 等。alter table 的有些操作只能靠 rebuild 表来完成。

误删数据

数据行

使用 delete 语句误删数据行时,可以用 Flashback 工具通过闪回把数据恢复过来,即修改 binlog 的内容,拿回原库重放。

能够使用这个方案的前提是,需要确保 binlog_format=row 和 binlog_row_image=FULL。

恢复数据比较安全的做法是恢复出一个备份,或者找一个从库作为临时库,然后在这个临时库上执行这些操作,确认过数据后再恢复回主库,免得出现对数据的二次破坏。

预防

设置 sql_safe_updates=on,当 delete 和 update 语句中没有写 where 条件,或者 where 条件里面没有包含索引字段的话,这条语句的执行就会报错。

数据表/库

使用 drop table 或者 truncate table 语句误删数据表时,或者使用 drop database 语句误删数据库时,主要有两种方式可以恢复。

方案一:使用全量备份加增量日志(实时备份 binlog)。

恢复的流程大概如下:

  1. 取最近一次全量备份;
  2. 用备份恢复出一个临时库;
  3. 从日志备份里面,取出备份点之后的日志;
  4. 把这些日志,除了误删除数据的语句外,全部应用到临时库。

如果是误删表,不能指定恢复某个表,所以恢复的速度很慢,且由于数据量很大,存在回复时间不可控的问题。

方案二:延迟复制备库。专门搭建延迟复制的备库,只要在延迟时间内发现问题,就能直接用备库快速恢复数据。

MySQL实例

使用 rm 命令误删整个 MySQL 实例时,对于高可用的集群而言,只要选出一个新的主库保证整个集群的正常工作,然后再把节点数据恢复,再接入集群即可。

最后

本文介绍了 MySQL 内存管理和磁盘管理。在内存管理部分,有一篇文章写的非常全面:(十二)MySQL之内存篇:深入探寻数据库内存与Buffer Pool的奥妙!

下一节将介绍 MySQL 存储过程和触发器。

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

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

相关文章

15 KVM虚拟机配置-体系架构相关配置

文章目录 15 KVM虚拟机配置-体系架构相关配置15.1 概述15.2 元素介绍15.3 AArch64架构配置示例15.4 x86_64架构配置示例 15 KVM虚拟机配置-体系架构相关配置 15.1 概述 XML中还有一部分体系架构相关的配置,这部分配置包括主板,CPU,一些与体…

【2023/05/10】Mitchel Resnick

Hello!大家好,我是霜淮子,2023倒计时第5天。 Share Her wistful face haunts my dreams like the rain at night. 译文: 她的热切的脸,如夜雨似的,搅扰着我的梦魂。 Once we dreamt that we were stra…

论文解读:DELPHI:用于蛋白质相互作用位点预测的精确深度集成模型

期刊: Briefings in Bioinformatics 出版日期 2022-11-22 websever:https://iasri-sg.icar.gov.in/pldbpred/ 网址: PlDBPred: a novel computational model for discovery of DNA binding proteins in plants | Briefings in Bioinformatics | Oxfo…

递归到动态规划- X-空间压缩技巧

空间压缩技巧的示例代码代码, LeetCode第64题 验证链接:力扣 package dataStructure.recurrence.practice;/*** https://leetcode.cn/problems/minimum-path-sum/* Leecode第64题* 给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左…

C++好难(6):模板初阶

【本节目标】 1. 泛型编程2. 函数模板3. 类模板 目录 【本节目标】 1.泛型编程 2.函数模板 概念: 格式: 原理: 实例化: 1.隐式实例化: 2.显式实例化 原则一: 原则二: 原则三&#…

数组存储与指针学习笔记(三)指针与数组

嵌入式C语言学习进阶系列文章 GUN C编译器拓展语法学习笔记(一)GNU C特殊语法部分详解 GUN C编译器拓展语法学习笔记(二)属性声明 GUN C编译器拓展语法学习笔记(三)内联函数、内建函数与可变参数宏 数组存储与指针学习笔记(一)数…

OpenCv更改颜色空间以及图像阈值

本文主要讲解以下几个方面: 如何将图片从一个颜色空间转换到另一个,例如 BGR 到 Gray,BGR 到 HSV 等。简单阈值法另外,我们会创建一个从图片中提取彩色对象的应用。 1.改变颜色空间 cv.cvtColor(img, flag) 参数flag表示颜色空间转换的方…

Hive语言2(大数据的核心:窗口函数)

1、Common Table Expressions(CTE)> 重点 公用表达式(CTE)是一个临时结果集,该结果集是从WITH子句中指定的简单查询派生而来的,该查询紧接在SELECT或INSERT关键字之前。 2.inner join(内连接)、left joi…

网页源码加密JavaScript程序,有效压缩和加密JS、Html、Css页面数据

我们知道,基于Des或Aes对称加密时,当明文和密码相同,则密文相同。而我们此次发布是WJLSymmetricEncryption4.js(点击链接跳转到下载页面)加密程序,当明文和密码相同,每次加密后的密文不相同&…

20230510vmlinux编译过程

1.进入linux内核源码目录下&#xff0c;打开Makefile文件&#xff0c;搜索vmlinux cmd_link-vmlinux \ $(CONFIG_SHELL) $< "$(LD)" "$(KBUILD_LDFLAGS)" "$(LDFLAGS_vmlinux)"; …

第10 CURD操作与RedisCache缓存的强制清理的实现

using System.Net; using Microsoft.Extensions.Caching.Distributed; using Core.Caching; using Core.Configuration; using StackExchange.Redis; namespace Services.Caching { /// <summary> /// 【Redis分布式缓存数据库软件管理器--类】 /// <remarks>…

索引 ---MySQL的总结(五)

索引 在mysql数据库之中&#xff0c;如果数据量过大&#xff0c;直接进行遍历会需要使用许多时间。这里使用空间换时间解决这一个问题。 目前就是从解决问题的这一个角度出发&#xff0c;需要增加搜索的速度&#xff0c;一定是要选择好用的数据结构进行搜索&#xff08;遍历的…

第十五届吉林省赛个人题解【中档题(不过可能对你来说是简单题)】(H、G、C)

文章目录 H. Visit the Park(STL)G. Matrix Repair(思维题)C.Random Number Generator(BSGS算法) H. Visit the Park(STL) 题意&#xff1a;给你一个无向图&#xff0c;每条边上都有一个数码&#xff0c;然后给你一个路径&#xff0c;每次你必须从Ai走到Ai1&#xff08;直接走…

【EHub_tx1_tx2_A200】Ubuntu18.04 + ROS_ Melodic + 锐驰LakiBeam 1L单线激光 雷达评测

大家好&#xff0c;我是虎哥&#xff0c;最近这段时间&#xff0c;又手欠入手了锐驰LakiBeam 1L激光雷达&#xff0c;实在是性价比太优秀&#xff0c;话说&#xff0c;最近激光雷达圈确实有点卷。锐驰官网的资料已经很丰富&#xff0c;我这里总结一下自己的简单测试经验&#x…

挑战14天学完Python---

抛弃了数学思维,引入了计算思维,计算思维是抽象和自动化相结合的结果 抽象:抽象问题的形式化逻辑 自动化:将抽象的结果通过程序自动实现 0.1在计算机内部转二进制 0.1转二进制 二进制的0.1与二进制0.2计算 结果再转十进制 在众多编程语言中 ,只有Python语言提供了复数类型.空间…

OpenCL编程指南-1.2OpenCL基本概念

OpenCL概念基础 面向异构平台的应用都必须完成以下步骤&#xff1a; 1&#xff09;发现构成异构系统的组件。 2&#xff09;探查这些组件的特征&#xff0c;使软件能够适应不同硬件单元的特定特性。 3&#xff09;创建将在平台上运行的指令块&#xff08;内核)。 4&#xff09…

紧跟 AI 步伐, Gitee 已支持 AI 模型托管

AI 时代已经来了&#xff01; 现在&#xff0c;越来越多的企业和个人开始使用 AI 技术来解决各种问题。想要了解 AI&#xff0c;那么就一定要了解 AI 模型&#xff0c;作为 AI 的核心技术之一&#xff0c;AI 模型为各种进阶的人工智能应用奠定了基础&#xff0c;从 ChatGPT 、…

Mysql 存储过程+触发器+存储函数+游标

视图&#xff08;view&#xff09; 虚拟存在的表&#xff0c;不保存查询结构&#xff0c;只保存查询的sql逻辑 语法 存储过程 实现定义并存储在数据库的一段sql语句的集合&#xff0c;可减少网络交互&#xff0c;提高性能&#xff0c;代码复用,内容包括&#xff1a;变量&am…

并发编程进阶

并发编程进阶 文章目录 并发编程进阶一、JMM1. JMM的定义&#xff1a;2. 内存屏障&#xff1a; 三. volatile四. as-if-serial五. happens-before六. 缓存一致性&#xff08;Cache coherence&#xff09;7. Synchronized1. synchronized 的使用2. synchronized底层原理 8. Conc…

Web3.0介绍与产业赛道(去中心化,金融与数字资产,应用与存储,区块链技术)

文章目录 1、web3.0时代——区块链技术2、产业赛道&#xff1a;去中心化金融与数字资产3、产业赛道&#xff1a;去中心化应用与存储4、区块链&#xff1a;基础设施与区块链安全和隐私 1、web3.0时代——区块链技术 Web3.0是什么 Web3.0是指下一代互联网技术&#xff0c;它将在…