MySQL实战解析底层---为什么我的MySQL会“抖“一下

news2024/12/25 23:47:26

目录

前言

SQL语句为什么变“慢”了

InnoDB刷脏页的控制策略


  • 前言

  • 一条SQL语句,正常执行的时候特别快,但是有时也不知道怎么回事,它就会变得特别慢,并且这样的场景很难复现,它不只随机,而且持续时间还很短
  • 看上去,这就像是数据库“抖”了一下
  • SQL语句为什么变“慢”了

  • InnoDB在处理更新语句的时候,只做了写日志这一个磁盘操作
  • 这个日志叫作redo log(重做日志),也就是酒店掌柜用来记账的粉板,在更新内存写完redo log后,就返回给客户端,本次更新成功
  • 做下类比的话,掌柜记账的账本是数据文件,记账用的粉板是日志文件(redo log),掌柜的记忆就是内存
    • 掌柜总要找时间把账本更新一下,这对应的就是把内存里的数据写入磁盘的过程,术语就是flush
    • 在这个flush操作执行之前,孔乙己的赊账总额,其实跟掌柜手中账本里面的记录是不一致的
    • 因为孔乙己今天的赊账金额还只在粉板上,而账本里的记录是老的,还没把今天的赊账算进去
  • 当内存数据页跟磁盘数据页内容不一致的时候,我们称这个内存页为“脏页”
  • 内存数据写入到磁盘后,内存和磁盘上的数据页的内容就一致了,称为“干净页”
  • 不论是脏页还是干净页,都在内存中
  • 在这个例子里,内存对应的就是掌柜的记忆
  • 接下来用一个示意图来展示一下“孔乙己赊账”的整个操作过程
  • 假设原来孔乙己欠账10文,这次又要赊9文

  • 回到开头的问题,不难想象,平时执行很快的更新操作,其实就是在写内存和日志,而MySQL偶尔“抖”一下的那个瞬间,可能就是在刷脏页(flush)
  • 那么,什么情况会引发数据库的flush过程呢?
  • 还是继续用酒店掌柜的这个例子,想一想:掌柜在什么情况下会把粉板上的赊账记录改到账本上?
  • 第一种场景是,粉板满了,记不下了
    • 这时候如果再有人来赊账,掌柜就只得放下手里的活儿,将粉板上的记录擦掉一些,留出空位以便继续记账
    • 当然在擦掉之前,他必须先将正确的账目记录到账本中才行
    • 这个场景,对应的就是InnoDB的redo log写满了
    • 这时候系统会停止所有更新操作,把checkpoint往前推进,redo log留出空间可以继续写

    • checkpoint可不是随便往前修改一下位置就可以的
    • 比如图中,把checkpoint位置从CP推进到CP’,就需要将两个点之间的日志(浅绿色部分),对应的所有脏页都flush到磁盘上
    • 之后,图中从write pos到CP’之间就是可以再写入的redo log的区域
  • 第二种场景是,这一天生意太好,要记住的事情太多,掌柜发现自己快记不住了,赶紧找出账本把孔乙己这笔账先加进去
    • 这种场景,对应的就是系统内存不足
    • 当需要新的内存页,而内存不够用的时候,就要淘汰一些数据页,空出内存给别的数据页使用
    • 如果淘汰的是“脏页”,就要先将脏页写到磁盘
    • 这时候难道不能直接把内存淘汰掉,下次需要请求的时候,从磁盘读入数据页,然后拿redo log出来应用不就行了?
    • 这里其实是从性能考虑的
    • 如果刷脏页一定会写盘,就保证了每个数据页有两种状态:
      • 一种是内存里存在,内存里就肯定是正确的结果,直接返回
      • 另一种是内存里没有数据,就可以肯定数据文件上是正确的结果,读入内存后返回;这样的效率最高
  • 第三种场景是,生意不忙的时候,或者打烊之后
    • 这时候柜台没事,掌柜闲着也是闲着,不如更新账本
    • 这种场景,对应的就是MySQL认为系统“空闲”的时候
    • 当然,MySQL“这家酒店”的生意好起来可是会很快就能把粉板记满的,所以“掌柜”要合理地安排时间
    • 即使是“生意好”的时候,也要见缝插针地找时间,只要有机会就刷一点“脏页”
  • 第四种场景是,年底了酒店要关门几天,需要把账结清一下
    • 这时候掌柜要把所有账都记到账本上,这样过完年重新开张的时候,就能就着账本明确账目情况了
    • 这种场景,对应的就是MySQL正常关闭的情况
    • 这时候,MySQL会把内存的脏页都flush到磁盘上,这样下次MySQL启动的时候,就可以直接从磁盘上读数据,启动速度会很快
  • 接下来分析一下上面四种场景对性能的影响
  • 其中,第三种情况是属于MySQL空闲时的操作,这时系统没什么压力,而第四种场景是数据库本来就要关闭了
  • 这两种情况下,你不会太关注“性能”问题
  • 所以这里主要来分析一下前两种场景下的性能问题
  • 第一种是“redo log写满了,要flush脏页”,这种情况是InnoDB要尽量避免的
  • 因为出现这种情况的时候,整个系统就不能再接受更新了,所有的更新都必须堵住
  • 如果从监控上看,这时候更新数会跌为0
  • 第二种是“内存不够用了,要先将脏页写到磁盘”,这种情况其实是常态
  • InnoDB用缓冲池(buffer pool)管理内存,缓冲池中的内存页有三种状态:
    • 第一种是,还没有使用的
    • 第二种是,使用了并且是干净页
    • 第三种是,使用了并且是脏页
  • InnoDB的策略是尽量使用内存,因此对于一个长时间运行的库来说,未被使用的页面很少
  • 而当要读入的数据页没有在内存的时候,就必须到缓冲池中申请一个数据页
  • 这时候只能把最久不使用的数据页从内存中淘汰掉:
    • 如果要淘汰的是一个干净页,就直接释放出来复用
    • 但如果是脏页呢,就必须将脏页先刷到磁盘,变成干净页后才能复用
  • 所以,刷脏页虽然是常态,但是出现以下这两种情况,都是会明显影响性能的:
    • 1-一个查询要淘汰的脏页个数太多,会导致查询的响应时间明显变长
    • 2-日志写满,更新全部堵住,写性能跌为0,这种情况对敏感业务来说,是不能接受的
  • 所以,InnoDB需要有控制脏页比例的机制,来尽量避免上面的这两种情况
  • InnoDB刷脏页的控制策略

  • 首先要正确地告诉InnoDB所在主机的IO能力,这样InnoDB才能知道需要全力刷脏页的时候,可以刷多快
  • 这就要用到innodb_io_capacity这个参数了,它会告诉InnoDB你的磁盘能力
  • 这个值建议设置成磁盘的IOPS
  • 其实,因为没能正确地设置innodb_io_capacity参数,而导致的性能问题也比比皆是
  • 例如主机磁盘用的是SSD,但是innodb_io_capacity的值设置的是300
  • 于是,InnoDB认为这个系统的能力就这么差,所以刷脏页刷得特别慢,甚至比脏页生成的速度还慢,这样就造成了脏页累积,影响了查询和更新性能
  • 虽然现在已经定义了“全力刷脏页”的行为,但平时总不能一直是全力刷吧?
  • 毕竟磁盘能力不能只用来刷脏页,还需要服务用户请求
  • 所以接下来看看InnoDB怎么控制引擎按照“全力”的百分比来刷脏页
  • 如果刷太慢,会出现什么情况?
  • 首先是内存脏页太多,其次是redo log写满
  • 所以,InnoDB的刷盘速度就是要参考这两个因素:
    • 一个是脏页比例
    • 一个是redo log写盘速度
  • InnoDB会根据这两个因素先单独算出两个数字
  • 参数innodb_max_dirty_pages_pct是脏页比例上限,默认值是75%
  • InnoDB会根据当前的脏页比例(假设为M),算出一个范围在0到100之间的数字,计算这个数字的伪代码类似这样:

  • InnoDB每次写入的日志都有一个序号,当前写入的序号跟checkpoint对应的序号之间的差值,假设为N
  • InnoDB会根据这个N算出一个范围在0到100之间的数字,这个计算公式可以记为F2(N)
  • F2(N)算法比较复杂,你只要知道N越大,算出来的值越大就好了
  • 然后,根据上述算得的F1(M)和F2(N)两个值,取其中较大的值记为R,之后引擎就可以按照innodb_io_capacity定义的能力乘以R%来控制刷脏页的速度
  • 图中的F1、F2就是上面通过脏页比例和redo log写入速度算出来的两个值

  • 现在知道了,InnoDB会在后台刷脏页,而刷脏页的过程是要将内存页写入磁盘
  • 所以,无论是你的查询语句在需要内存的时候可能要求淘汰一个脏页,还是由于刷脏页的逻辑会占用IO资源并可能影响到了你的更新语句,都可能是造成你从业务端感知到MySQL“抖”了一下的原因
  • 要尽量避免这种情况,你就要合理地设置innodb_io_capacity的值,并且平时要多关注脏页比例,不要让它经常接近75%
  • 其中,脏页比例是通过Innodb_buffer_pool_pages_dirty/Innodb_buffer_pool_pages_total得到的
  • 接下来再看一个有趣的策略
  • 一旦一个查询请求需要在执行过程中先flush掉一个脏页时,这个查询就可能要比平时慢了
  • 而MySQL中的一个机制,可能让你的查询会更慢:
    • 在准备刷一个脏页的时候,如果这个数据页旁边的数据页刚好是脏页,就会把这个“邻居”也带着一起刷掉
    • 而且这个把“邻居”拖下水的逻辑还可以继续蔓延,也就是对于每个邻居数据页,如果跟它相邻的数据页也还是脏页的话,也会被放到一起刷
  • 在InnoDB中,innodb_flush_neighbors 参数就是用来控制这个行为的,值为1的时候会有上述的“连坐”机制,值为0时表示不找邻居,自己刷自己的
  • 找“邻居”这个优化在机械硬盘时代是很有意义的,可以减少很多随机IO
  • 机械硬盘的随机IOPS一般只有几百,相同的逻辑操作减少随机IO就意味着系统性能的大幅度提升
  • 而如果使用的是SSD这类IOPS比较高的设备的话,建议把innodb_flush_neighbors的值设置成0
  • 因为这时候IOPS往往不是瓶颈,而“只刷自己”,就能更快地执行完必要的刷脏页操作,减少SQL语句响应时间
  • 在MySQL 8.0中,innodb_flush_neighbors参数的默认值已经是0了

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

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

相关文章

STM32挂载SD卡基于Fatfs文件系统读取文件信息

STM32挂载SD卡基于Fatfs文件系统读取文件信息 🔖本例程基于正点原子标准库修改而来。 📍FatFs 相关API函数网站:http://elm-chan.org/fsw/ff/00index_e.html 🌴分别测试了SD卡模块以及Mini SD卡模块。 🌿STM32f1单片…

代码随想录二刷day29 | 回溯之 491.递增子序列 46.全排列 47.全排列 II

day29 491.递增子序列回溯三部曲 46.全排列回溯三部曲 47.全排列 II 491.递增子序列 题目链接 解题思路: 回溯三部曲 递归函数参数 本题求子序列,很明显一个元素不能重复使用,所以需要startIndex,调整下一层递归的起始位置。…

【Python 基础篇】Python各种运算符详解

文章目录 引言一、算术运算符二、比较运算符三、逻辑运算符四、赋值运算符总结 引言 在 Python 编程中,运算符是用于执行各种数学和逻辑操作的特殊符号。它们使我们能够对变量和值进行各种计算和比较。本篇博客将深入探讨 Python 中的常见运算符,并通过…

【如何将多个类似 DDR-dataset.zip.010 文件文件合并成一个zip文件,然后解压】

如何将多个类似 DDR-dataset.zip.010 文件文件合并成一个zip文件,然后解压 问题描述 DDR-dataset.zip.01、DDR-dataset.zip.02、DDR-dataset.zip.03、…、DDR-dataset.zip.010,如何将他们合并到一起并解压? 解决方法 Windows 系统 在Windo…

原生Jdbc获取库、表、字段

文章目录 一、简介1、概述2、Jdbc获取连接3、执行器 二、获取链接1、获取链接2、关闭连接3、Statement4、PrepatedStatement5、 ResultSet6、ResultSetMetaData 三、执行SQL2.1 增/删/改2.2 查询 四、获取库、表结构1、获取Catalog2、获取库列表3、获取表名4、获取字段 一、简介…

为什么本地部署的低代码平台更有优势?

编者按:快速发展的企业需要跟上不断变化的市场趋势。在这种环境下,低代码开发平台可以成为企业快速进入市场的利器。低代码开发的优势可以影响新软件的交付速度,而可视化开发是推动这种无与伦比的速度的关键功能。私有化部署方案和源码交付机…

27-2BP_Adaboost强分类器公司财务预管建模——强分类器和弱分类器(附matlab程序)

1.简述 Adaboost算法的思想是合并多个“弱”分类器的输出以产生有效分类。其主要步骤为:首先给出弱学习算法和样本空间(x,y),从样本空间中找出m组训练数据,每组训练数据的权重都是1/m。然后用弱学习算法迭代运算T次&am…

SIP协议学习笔记

SIP 协议(Session initialization Protocol)会话发起协议 是IETF制定的多媒体通信协议,是一个基于文本的应用层控制协议,用于建立,修改和终止IP网上的双方或多方的多媒体会话,支持代理、重定向、登记定位用户等功能 支持用户的移动&#xff…

Packet Tracer - 使用思科 IOS 配置 DHCP

Packet Tracer - 使用思科 IOS 配置 DHCP 地址分配表 设备 接口 IPv4 地址 子网掩码 默认网关 R1 G0/0 192.168.10.1 255.255.255.0 不适用 S0/0/0 10.1.1.1 255.255.255.252 不适用 R2 G0/0 192.168.20.1 255.255.255.0 不适用 G0/1 已分配 DHCP 已分配 …

python安装/卸载模块方法步骤详解(附详细图解)

在日常工作中会需要安装或者卸载Python模块.于是我整理了一下,下面这篇文章主要给大家介绍了关于python安装/卸载模块的相关资料,文中通过图文介绍的非常详细,需要的朋友可以参考下 以pygame模块举例 1,通过pycharm导入 (1)直接点击install …

Redis 2023面试5题(三)

一、Redis集群数据hash分片算法是怎么回事? Redis集群数据hash分片算法是一种将数据分散存储在不同的节点上来实现的机制。具体来说,Redis集群将数据分成16384个槽位,每个槽位对应一个节点。当需要访问某个key时,Redis会根据key的…

nginx主配置文件及实战案例

文章目录 一.nginx主配置文件nginx.conf1.认识nginx服务的主配置文件2.全局配置3.I/O事件配置4.HTTP配置5.检查配置文件是否正确6.浏览器测试7.总配置文件图示7.1 nginx总配置文件的三个模块7.2 HTTP文件配置的图示&am…

【Matlab】语音信号分析与处理实验报告

一、目的 使用Matlab分析与设计实验,理解与掌握以下知识点: 1、信号的采样、频谱混叠 2、信号的频谱分析 3、信号的幅度调制与解调方法 4、理想滤波器的时域和频域特性 5、数字滤波器的设计与实现 二、内容 1、录制一段个人的语音信号 2、采用合适的频…

Unity3D制作一个会移动的方块(还不会移动照相机)

学习Unity3D这么久了,如果你还不会制作一个按下WASD就可以移动的方块的话,那么你的学习将没有一点成就感,我学习的时候,我决定先学习移动,这样我就会对Unity更加感兴趣,学习起来的动力会更为充足 先创建一…

Nseeus安装及使用教程

Nessus是一款目前使用较多的系统漏洞扫描与分析软件 文章目录 Nessus下载安装使用启动:https://localhost:8834/ Nessus Nessus是一款目前使用较多的系统漏洞扫描与分析软件 下载 下载链接:https://www.tenable.com/downloads/nessus 安装 傻瓜式安装 使用 最…

Baumer工业相机堡盟工业相机如何使用新版本NEOAPI SDK控制相机数据流的开启和关闭(C++)

Baumer工业相机堡盟工业相机如何使用新版本NEOAPI SDK控制相机数据流的开启和关闭(C) Baumer工业相机Baumer工业相机NEOAPI SDK的技术背景Baumer工业相机使用NEOAPISDK控制相机数据流的方式1.引用合适的类文件2.使用NEOAPISDK控制相机数据流的方式2.使用…

Xshell 连接虚拟机Ubuntu系统失败解决方案

背景知识: Xshell 是一个强大的安全终端模拟软件,可以进行远程登录,它支持 SSH1, SSH2, 以及 Microsoft Windows 平台的 TELNET 协议。 xshell通过ip连接,所以需要知道虚拟机的IP地址 使用XShell的主要目的是在Windows环境下登…

leetcode111. 二叉树的最小深度(java)

二叉树的最小深度 leetcode111. 二叉树的最小深度题目描述 DFS 深度优先遍历解题思路代码演示 BFS 广度优先遍历解题思路代码演示 往期经典 leetcode111. 二叉树的最小深度 来源:力扣(LeetCode) 链接:https://leetcode.cn/problem…

基于立创EDA的原理图设计

目录 学习目标 一、开发中原理图的作用 1.1 原理图 1.2 产品开发原理图设计阶段 1.3 原理图中的具体工作内容 二、 立创EDA软件使用基础 2.1 立创EDA电路设计软件 2.2 新建工程 2.3 设计元件原理图封装 三、项目实战(单片机最小系统) 学习目标…

Kaggle 比赛总结:BirdCLEF 2023

赛题名称:BirdCLEF 2023赛题任务:识别音景中的鸟叫声赛题类型:语音识别 https://www.kaggle.com/competitions/birdclef-2023文章目录 一、比赛背景二、比赛任务三、评价方法四、优胜方案4.1 第一名4.2 第二名4.3 第三名4.4 第四名4.5 第五名…