MySQL 实战 45 讲
林晓斌
网名丁奇,前腾讯云数据库负责人
224873 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 49 讲
实践篇 (37讲)
特别放送 (1讲)
结课测试 (1讲)
MySQL 实战 45 讲
15
15
1.0x
00:00/00:00
登录|注册

12 | 为什么我的MySQL会“抖”一下?

日志写满
脏页比例过高
MySQL正常关闭
MySQL空闲时
系统内存不足
粉板满了
控制刷脏页的速度
F1(M)和F2(N)的计算
影响性能
场景
脏页 vs 干净页
返回给客户端
写日志(redo log)
其他优化思路
学号规则和存储方式
正向和反向的前缀索引
监控脏页比例
控制刷脏页的方法
性能问题的原因
innodb_flush_neighbors参数
刷脏页速度策略
脏页比例和redo log写入速度
innodb_io_capacity参数
刷脏页(flush)
内存数据页与磁盘数据页
InnoDB处理更新语句
学号字段创建索引的方法
小结
InnoDB刷脏页的控制策略
WAL机制
上期问题时间
为什么我的MySQL会“抖”一下?

该思维导图由 AI 生成,仅供参考

平时的工作中,不知道你有没有遇到过这样的场景,一条 SQL 语句,正常执行的时候特别快,但是有时也不知道怎么回事,它就会变得特别慢,并且这样的场景很难复现,它不只随机,而且持续时间还很短。
看上去,这就像是数据库“抖”了一下。今天,我们就一起来看一看这是什么原因。

你的 SQL 语句为什么变“慢”了

在前面第 2 篇文章《日志系统:一条 SQL 更新语句是如何执行的?》中,我为你介绍了 WAL 机制。现在你知道了,InnoDB 在处理更新语句的时候,只做了写日志这一个磁盘操作。这个日志叫作 redo log(重做日志),也就是《孔乙己》里咸亨酒店掌柜用来记账的粉板,在更新内存写完 redo log 后,就返回给客户端,本次更新成功。
做下类比的话,掌柜记账的账本是数据文件,记账用的粉板是日志文件(redo log),掌柜的记忆就是内存。
掌柜总要找时间把账本更新一下,这对应的就是把内存里的数据写入磁盘的过程,术语就是 flush。在这个 flush 操作执行之前,孔乙己的赊账总额,其实跟掌柜手中账本里面的记录是不一致的。因为孔乙己今天的赊账金额还只在粉板上,而账本里的记录是老的,还没把今天的赊账算进去。
当内存数据页跟磁盘数据页内容不一致的时候,我们称这个内存页为“脏页”。内存数据写入到磁盘后,内存和磁盘上的数据页的内容就一致了,称为“干净页”
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文通过对InnoDB的工作机制进行比喻,解释了数据库“抖动”现象的原因。首先介绍了InnoDB的WAL机制,即写日志和内存数据页的刷新过程。通过咸亨酒店掌柜的例子,分析了导致数据库刷新过程的几种情况,如redo log写满、系统内存不足等。指出这些情况会明显影响数据库性能,尤其是当查询需要淘汰大量脏页或者日志写满时,会导致查询响应时间明显变长甚至更新操作完全堵塞。最后,提到InnoDB需要有控制脏页比例的机制来尽量避免性能问题的发生。文章通过生动的比喻和技术分析,帮助读者快速了解了数据库“抖动”现象的原因和对性能的影响,为数据库管理员和开发人员提供了有益的技术参考。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《MySQL 实战 45 讲》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(194)

  • 最新
  • 精选
  • Ryoma
    置顶
    关于粉板和redo log的类比我觉得有一点不太合适:redo log记录的是实时欠款,比如账本中是10文,又欠了9文,此时redo log 记录的是19;而粉板的话,只会追加某人欠款+9文,不会关注原来已欠款多少(不然某人赊账时,我还需要找到账本中的这个人,才知道他之前欠款多少,我觉得这个场景跟MySQL中的场景还是有区别的)

    作者回复: Redo log里也是记的+9哦😄

    2018-12-12
    29
    45
  • yesir
    置顶
    我观察了下公司的数据库确实发现了抖动现象,有几个问题, 1)Innodb_buffer_pool_pages_total这个值很大,百万级别的,而且数值不像是人为设置上去的,是怎么来的呢? 2)Innodb_buffer_pool_pages_dirty达到4万多的时候就开始flush了,脏页比例是75,这肯定是远达不到的,ssd磁盘,innodb_io_capacity是200,肯定可以提高。文章中说flush的触发条件有2个,一个是内存不够了,一个是redo log 满了,那么我这个场景是哪种情况呢

    作者回复: 1) 这个是innodb 数据页总是,过百万是正常的,16K一个,Bufree pool size 16G 就是100万了 2)你这个例子就是io_capacity设太小了…

    2018-12-11
    8
    55
  • 某、人
    置顶
    redo log是关系型数据库的核心啊,保证了ACID里的D。所以redo log是牵一发而动全身的操作 按照老师说的当内存数据页跟磁盘数据页不一致的时候,把内存页称为'脏页'。如果redo log 设置得太小,redo log写满.那么会涉及到哪些操作呢,我认为是以下几点: 1.把相对应的数据页中的脏页持久化到磁盘,checkpoint往前推 2.由于redo log还记录了undo的变化,undo log buffer也要持久化进undo log 3.当innodb_flush_log_at_trx_commit设置为非1,还要把内存里的redo log持久化到磁盘上 4.redo log还记录了change buffer的改变,那么还要把change buffer purge到idb 以及merge change buffer.merge生成的数据页也是脏页,也要持久化到磁盘 上述4种操作,都是占用系统I/O,影响DML,如果操作频繁,会导致'抖'得向现在我们过冬一样。 但是对于select操作来说,查询时间相对会更快。因为系统脏页变少了,不用去淘汰脏页,直接复用 干净页即可。还有就是对于宕机恢复,速度也更快,因为checkpoint很接近LSN,恢复的数据页相对较少 所以要控制刷脏的频率,频率快了,影响DML I/O,频率慢了,会导致读操作耗时长。 我是这样想的这个问题,有可能不太对,特别是对于第4点是否会merge以及purge,还需要老师的解答

    作者回复: 抖得像过冬一样,😄👍🏿 你说得很对,第4点没错的,出现这种情况的时候,连change buffer的优化也没意义了

    2018-12-10
    15
    213
  • Tony Du
    置顶
    当内存不够用了,要将脏页写到磁盘,会有一个数据页淘汰机制(最久不使用),假设淘汰的是脏页,则此时脏页所对应的redo log的位置是随机的,当有多个不同的脏页需要刷,则对应的redo log可能在不同的位置,这样就需要把redo log的多个不同位置刷掉,这样对于redo log的处理不是就会很麻烦吗?(合并间隙,移动位置?) 另外,redo log的优势在于将磁盘随机写转换成了顺序写,如果需要将redo log的不同部分刷掉(刷脏页),不是就在redo log里随机读写了么?

    作者回复: 好问题。 其实由于淘汰的时候,刷脏页过程不用动redo log文件的。 这个有个额外的保证,是redo log在“重放”的时候,如果一个数据页已经是刷过的,会识别出来并跳过。

    2018-12-10
    47
    448
  • melon
    又思考了一下,请老师帮忙看一下理解的对不对:buffer pool里维护着一个脏页列表,假设现在redo log 的 checkpoint 记录的 LSN 为 10,现在内存中的一干净页有修改,修改后该页的LSN为12,大于 checkpoint 的LSN,则在写redo log的同时该页也会被标记为脏页记录到脏页列表中,现在内存不足,该页需要被淘汰掉,该页会被刷到磁盘,磁盘中该页的LSN为12,该页也从脏页列表中移除,现在redo log 需要往前推进checkpoint,到LSN为12的这条log时,发现内存中的脏页列表里没有该页,且磁盘上该页的LSN也已经为12,则该页已刷脏,已为干净页,跳过。

    作者回复: 对的。👍🏿

    2018-12-11
    27
    159
  • jimmy
    老师,我想问一下,innodb是如何知道一个页是不是脏页的,是有标记位还是通过redolog的ckeckpoint来确定的?

    作者回复: 每个数据页头部有LSN,8字节,每次修改都会变大。 对比这个LSN跟checkpoint 的LSN,比checkpoint小的一定是干净页

    2018-12-10
    11
    126
  • 大白给小白讲故事
    “内存不够用了,要先将脏页写到磁盘“和“redo log 写满了,要 flush 脏页”可以理解为一个脏页本身占用内存,释放内存需要将脏页写入到磁盘才能释放。而redo log写满只有当redo log对应的脏页flush到磁盘上才能释放对应空间。有几个问题: 1、“内存不够用了,要先将脏页写到磁盘“redo log对应的空间会释放嘛?“redo log 写满了,要 flush 脏页”对应的内存页会释放嘛? 2、将脏页flush到磁盘上是直接将脏页数据覆盖到对应磁盘上的数据?还是从磁盘上取到数据后取根据redo log记录进行更新后再写入到磁盘? 3、redo log是怎么记录对应脏页是否已经flush了?如果断电了重启导致内存丢失,前面几章说通过redo log进行数据恢复那redo log又怎么去释放空间?

    作者回复: 1. Redolog 的空间是循环使用的,无所谓释放。 对应的内存页会变成干净页。但是等淘汰的时候才会逐出内存 2. 好问题,前者 3. 不用记,重启了就从checkpoint 的位置往后扫。 如果已经之前刷过盘的, 不会重复应用redi log。 好问题

    2018-12-10
    11
    77
  • 运斤成风
    老师好,flush和purge是不是还是有区别的?flush主要指刷新脏页,和clean进程相关?而purge是清理不再被使用的undo信息。

    作者回复: 对, flush 一般是说刷脏页, purge一般是指清undo log, merge一般是指应用change buffer

    2018-12-26
    2
    66
  • 张永志
    100M的redo很容易写满,系统锁死,触发检查点推进,导致写操作卡住。由于主机IO能力很强,检查点会很快完成,卡住的写操作又很快可以执行。循环往复,现象就是写操作每隔一小段时间执行就会变慢几秒。

    作者回复: 准确

    2018-12-10
    3
    56
  • skyoo
    很多测试人员再做压力测试的时候 出现刚开始 insert update 很快 一会 就出现很慢,并且延迟很大,大部分是因为redo log 设置太小 引起的,完美诠释

    作者回复: 👍🏿 常见的误用场景

    2018-12-11
    49
收起评论
显示
设置
留言
99+
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部