• mysql的缓存页对LRU的改进;预读机制;及对应的调优


    概述

    LUR(Least Recently Used):最近未使用。

    传统的LRU就是维护了一个链表,链表的头部是最近使用的元素,尾部是最长时间没使用的元素。

    mysqlbufferpool里有许多的缓存页,从磁盘中的读取的数据就存放在这些缓存页中供mysql操作,默认的缓存页大小是16Kb

    改造的原因

    mysql有时会有这样的操作场景,就是对某个大数据量的表进行全表扫描。那么此时会将buffer pool中的缓存页全部淘汰掉,存进这些全表扫描的数据。那么当下一波热点数据的请求进来的时候,就又需要从磁盘去读取数据到缓存页中,会导致IO开销增加。

    所以MYSQLLRU进行了改造,分为冷/热两部分LRU链表。当新的数据要拉进缓存但是缓存页的数据满了的时候,就先开始淘汰冷链中的页数据。当冷链中的数据在1秒内被再次访问的时候,不会放到热链中去,只有在1秒之后被再次访问了,才会放到热链的头部去。

    这个时间由innodb_old_blocks_time 控制,查询语句

    show variables like 'innodb_old_blocks_time';
    
    • 1

    结构图如下所示
    在这里插入图片描述

    mysql的预读

    什么是预读:当从磁盘上读取一个页的时候,把相邻的其他页也读进来。

    这种机制带来的好处:可以节省磁盘io的时间,直接从内存中读取数据。

    触发情况:

    顺序访问了磁盘上一个区的多个数据页,当这个数量超过56(默认的阈值)的时候,innodb会触发预读机制。这个参数由innodb_read_ahead_threshold控制,查询语句

    show variables like 'innodb_read_ahead_threshold';
    
    • 1

    对应的调优

    MySQL 的数据最终是存储在磁盘上的,每次查询数据时,我们先需要把数据加载进缓存,然后读取,如果每次查询的数据都已经存在于缓存了,那么就不用去磁盘读取,避免了一次磁盘 IO,这是我们最期望的。因此为了尽量在 LRU 链表中缓存更多的缓存页,我们「可以根据服务器的配置,尽量调大 Buffer Pool 的大小。

    可以通过如下命令去查看 Buffer Pool 的大小以及 Buffer Pool 实例的个数。

    # buffer pool大小
    show variables like 'innodb_buffer_pool_size';
    # buffer pool实例个数
    show variables like 'innodb_buffer_pool_instances';
    
    • 1
    • 2
    • 3
    • 4

    缓存命中率、缓存页的空闲数、脏页数量、LRU 链表中缓存页个数、冷热数据的比例、磁盘 IO 读取的数据页数量等信息。可以通过如下命令查看:

    show engine innodb status;
    
    • 1

    在这里插入图片描述

    如果看到 youngs/s 这个值较高,说明数据从冷数据区移到热数据的频率较大,因此可以适当调大热数据所占的比例,也就是减小innodb_old_blocks_pct参数的值,也可以调大innodb_old_blocks_time参数的值

    如果看到 non-youngs/s 这个值较高,说明数据被加载进缓存当中后,没有被移动到热数据区,这是因为在 1s 内被访问了,这很可能是全表扫描造成的,这个时候就可以去检查一下代码,是不是SQL语句写得不恰当。

  • 相关阅读:
    Cobalt Strike
    前端工程化精讲第二十课 流程优化:部署流程中的构建流程策略优化
    带你玩转序列模型之Bleu得分&注意力模型&语音识别
    UG NX二次开发(C++)-采用NXOpen方法创建同步建模中的偏置曲面
    (附源码)ssm码农论坛 毕业设计 231126
    flutter解决多个类名重名问题
    小白开发程序的一天
    harvard dataverse数据公开上传网站-数据库repository
    c数组与结构体
    7、NoClassDefFoundError: sun/misc/BASE64Encoder
  • 原文地址:https://blog.csdn.net/weixin_43944305/article/details/126300092