一文带你了解MySQL数据库Innodb_buffer_pool_size

news2024/11/24 6:03:31

前言

上篇文章介绍了MySQL中的存储引擎层主要负责数据的写入和读取,与底层的文件进行交互。MySQL在5.5 版本以后,MySQL默认存储引擎为 InnoDB,他的主要特性有:

  • DML 操作(增、删、改)遵循 ACID(事务安全表) 模型,支持事务。
  • 行级锁,提高并发访问性能。
  • 支持外键(FOREIGN KEY)约束,保证数据的完整性和正确性。

本文章收录在MySQL性能优化+原理+实战专栏,更多优质内容点击此处查看。

在这里插入图片描述

目录

  • 一、InnoDB架构
  • 二、Buffer Pool
    • 2.1 什么是缓冲池
    • 2.2 缓冲池大小的设置
    • 2.3 缓冲池的管理
      • 2.3.1 Buffer Pool的初始化
      • 2.3.2 如何管理空闲页
      • 2.3.3 如何管理脏页
      • 2.3.4 如何提高缓存命中率?
      • 2.3.5 预读失效
      • 2.3.6 Buffer Pool污染
      • 2.3.7 脏页什么时候会被刷入磁盘?
    • 2.4 缓冲池的高并发
    • 2.5 缓冲池数据预热(了解)
    • 2.6 缓冲池的案例
      • 2.6.1 大量的全表扫描
      • 2.6.2 没有大量的全表扫描

一、InnoDB架构

下面是 InnoDB 引擎架构图,左侧为内存结构,右侧为磁盘结构

在这里插入图片描述

二、Buffer Pool

2.1 什么是缓冲池

Buffer Pool是MySQL中最重要的内存组件,介于外部系统和存储引擎之间的一个缓存区,里面可以缓存磁盘上经常操作的真实数据,在执行增删改查操作时,先操作缓冲池中的数据(若缓冲池没有数据,则从磁盘加载并缓存),然后再以一定频率刷新到磁盘,从而减少磁盘 IO,加快处理速度。在缓冲池中不仅缓存了索引页和数据页,还包含了 undo 页、插入缓存(insert page)、自适应哈希索引以及 InnoDB 的锁信息等。
在这里插入图片描述

2.2 缓冲池大小的设置

缓冲池的配置通过变量innodb_buffer_pool_size来设置,通常它的大小占用内存60%-80%,MySQL默认是134217728字节,也就是128M。

mysql> show variables like '%innodb_buffer_pool_size%';
+-------------------------+-----------+
| Variable_name           | Value     |
+-------------------------+-----------+
| innodb_buffer_pool_size | 134217728 |
+-------------------------+-----------+
1 row in set (0.01 sec)

我们可以通过set persist命令设置缓冲池的大小

[root@mysql2 ~]# free -h
              total        used        free      shared  buff/cache   available
Mem:            15G        1.1G         12G         13M        1.4G         14G
Swap:           15G          0B         15G

15X0.7X1024X1024X1024=11274289152

mysql> set persist innodb_buffer_pool_size=11274289152;
Query OK, 0 rows affected (0.00 sec)

mysql> show variables like '%innodb_buffer_pool_size%';
+-------------------------+-------------+
| Variable_name           | Value       |
+-------------------------+-------------+
| innodb_buffer_pool_size | 11274289152 |
+-------------------------+-------------+
1 row in set (0.01 sec)

那我们如何判断缓冲池的大小是否合理,可以通过:

  • show engine innodb status 如果Free buffers值为0,表示缓存池设置过小

  • show status like '%buffer_pool_wait%' 如果value值大于0,表示缓存池设置过小

mysql> show engine innodb status \G;
**********忽略部分**********
BUFFER POOL AND MEMORY
----------------------
Total large memory allocated 0
Total large memory allocated表示Buffer Pool向操作系统申请的连续内存空间大小,包括全部控制块、缓存页、以及碎片的字节大小

Dictionary memory allocated 1290731
Dictionary memory allocated表示数据字典信息分配的内存空间的字节大小,注意这个内存空间和Buffer Pool没啥关系,不包括在Total memory allocated中

Buffer pool size   688067
Buffer pool size 表示该Buffer Pool可以容纳多少缓存页,注意,单位是页!

Free buffers       680866
Free buffers表示当前Buffer Pool还有多少空闲缓存页,也就是free链表中还有多少个节点

Database pages     7194
Database pages表示LRU链表中的页的数量,包含young和old两个区域的节点数量

Old database pages 2650
Old database pages表示LRU链表old区域的节点数量

Modified db pages  0
Modified db pages表示脏页数量,也就是flush链表中节点的数量。

Pending reads      0
Pending reads表示正在等待从磁盘上加载到Buffer Pool中的页面数量,需要注意的s当准备从磁盘中加载某个页面时,会先为这个页面在Buffer Pool中分配一个缓存页以及它对应的控制块,然后把这个控制块添加到LRU的old区域的头部,但是这个时候真正的磁盘页并没有被加载进来,Pending reads的值会跟着加1。

Pending writes: LRU 0, flush list 0, single page 0
Pending writes表示即将从LRU、flush链表和单个页面刷新到磁盘中的页面数量


Pages made young 23621, not young 178247
Pages made young表示LRU链表中曾经从old区域移动到young区域头部的节点数量
not young表示在将innodb_old_blocks_time设置的值大于0时,首次访问或者后续访问某个处在old区域的节点时由于不符合时间间隔的限制而不能将其移动到young区域头部时,Page made not young的值会加10.00 youngs/s, 0.00 non-youngs/s
youngs/s表示每秒从old区域被移动到young区域头部的节点数量
non-youngs/s表示每秒由于不满足时间限制而不能从old区域移动到young区域头部的节点数量

Pages read 7056, created 29120, written 45996
0.00 reads/s, 0.00 creates/s, 0.00 writes/s
表示读取,创建,写入了多少页。后边跟着读取、创建、写入的速率

Buffer pool hit rate 1000 / 1000, young-making rate 0 / 1000 not 0 / 1000
Buffer pool hit rate表示在过去某段时间,平均访问1000次页面,有多少次该页面已经被缓存到Buffer Pool了
young-making rate表示在过去某段时间,平均访问1000次页面,有多少次访问使页面移动到young区域的头部了
not (young-making rate)表示在过去某段时间,平均访问1000次页面,有多少次访问没有使页面移动到young区域的头部

Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
Pages read ahead表示每秒读入的pages
evicted without access表示每秒读出的pages
Random read ahead表示随机读人的pages

LRU len: 7194, unzip_LRU len: 0
LRU len表示LRU链表中节点的数量

I/O sum[5]:cur[0], unzip sum[0]:cur[0]
I/O sum表示最近50s读取磁盘页的总数
I/O cur表示现在正在读取的磁盘页数量
I/O unzip sum表示最近50s解压的页面数量
I/O unzip cur表示正在解压的页面数量

mysql> show status like '%buffer_pool_wait%';
+------------------------------+-------+
| Variable_name                | Value |
+------------------------------+-------+
| Innodb_buffer_pool_wait_free | 0     |
+------------------------------+-------+
1 row in set (0.00 sec)

或者通过分析InnoDB缓冲池的性能来验证。

可以使用以下公式计算InnoDB缓冲池性能:
Performance = innodb_buffer_pool_reads / innodb_buffer_pool_read_requests * 100
innodb_buffer_pool_reads:表示InnoDB缓冲池无法满足的请求数。需要从磁盘中读取。
innodb_buffer_pool_read_requests:表示从内存中读取逻辑的请求数。
例如,在我的服务器上,检查当前InnoDB缓冲池的性能

mysql> show status like 'innodb_buffer_pool_read%';
+---------------------------------------+-------+
| Variable_name                         | Value |
+---------------------------------------+-------+
| Innodb_buffer_pool_read_ahead_rnd     | 0     |
| Innodb_buffer_pool_read_ahead         | 839   |
| Innodb_buffer_pool_read_ahead_evicted | 0     |
| Innodb_buffer_pool_read_requests      | 62567 |
| Innodb_buffer_pool_reads              | 3043  |
+---------------------------------------+-------+
5 rows in set (0.01 sec)

Innodb_buffer_pool_reads/Innodb_buffer_pool_read_requests*100 即 3043 /62567 *100=4.86

意味着InnoDB可以满足缓冲池本身的大部分请求。从磁盘完成读取的百分比非常小。因此无需增加innodb_buffer_pool_size值。

InnoDB buffer pool 命中率:

InnoDB buffer pool 命中率 = innodb_buffer_pool_read_requests / (innodb_buffer_pool_read_requests + innodb_buffer_pool_reads ) * 100

此值低于99%,则可以考虑增加innodb_buffer_pool_size。

InnoDB缓冲池状态变量有哪些?

可以运行以下命令进行查看:show status like '%innodb_buffer_pool_pages%'

mysql> show status like '%innodb_buffer_pool_pages%';
+----------------------------------+--------+
| Variable_name                    | Value  |
+----------------------------------+--------+
| Innodb_buffer_pool_pages_data    | 4025   |
| Innodb_buffer_pool_pages_dirty   | 0      |
| Innodb_buffer_pool_pages_flushed | 215    |
| Innodb_buffer_pool_pages_free    | 684034 |
| Innodb_buffer_pool_pages_misc    | 69     |
| Innodb_buffer_pool_pages_total   | 688128 |
+----------------------------------+--------+
6 rows in set (0.01 sec)

说明:

  • Innodb_buffer_pool_pages_dataInnoDB缓冲池中包含数据的页数。 该数字包括脏页面和干净页面。 使用压缩表时,报告的Innodb_buffer_pool_pages_data值可能大于Innodb_buffer_pool_pages_total。

  • Innodb_buffer_pool_pages_dirty显示在内存中修改但尚未写入数据文件的InnoDB缓冲池数据页的数量(脏页刷新)。

  • Innodb_buffer_pool_pages_flushed表示从InnoDB缓冲池中刷新脏页的请求数。

  • Innodb_buffer_pool_pages_free显示InnoDB缓冲池中的空闲页面

  • Innodb_buffer_pool_pages_misc InnoDB缓冲池中的页面数量很多,因为它们已被分配用于管理开销,例如行锁或自适应哈希索引。此值也可以计算为Innodb_buffer_pool_pages_total - Innodb_buffer_pool_pages_free - Innodb_buffer_pool_pages_data。

  • Innodb_buffer_pool_pages_totalInnoDB缓冲池的总大小,以page为单位。

  • innodb_buffer_pool_reads表示InnoDB缓冲池无法满足的请求数。需要从磁盘中读取。

  • innodb_buffer_pool_read_requests它表示从内存中逻辑读取的请求数。

  • innodb_buffer_pool_wait_free通常,对InnoDB缓冲池的写入发生在后台。 当InnoDB需要读取或创建页面并且没有可用的干净页面时,InnoDB首先刷新一些脏页并等待该操作完成。 此计数器计算这些等待的实例。 如果已正确设置innodb_buffer_pool_size,则此值应该很小。如果大于0,则表示InnoDb缓冲池太小。

  • innodb_buffer_pool_write_request表示对缓冲池执行的写入次数。

2.3 缓冲池的管理

2.3.1 Buffer Pool的初始化

在 MySQL 启动的时候,InnoDB 会为 Buffer Pool 申请一片连续的内存空间,然后按照默认的16KB的大小划分出一个个的页, Buffer Pool 中的页就叫做缓存页。此时这些缓存页都是空闲的,之后随着执行增删改查操作时,才会有磁盘上的数据页被缓存到 Buffer Pool 中。

为了更好的管理这些在 Buffer Pool 中的缓存页,InnoDB 为每一个缓存页的最前面都创建了一个内存大小一样的控制块,里面包括缓存页的表空间、页号、缓存页地址、链表节点等。

在这里插入图片描述每一个控制块都对应一个缓存页,在分配控制块和缓存页后,剩余的空间不够一对控制块和缓存页的大小,就被称为碎片空间

2.3.2 如何管理空闲页

我们知道Buffer Pool 是一片连续的内存空间,当 MySQL 运行一段时间后,这片连续的内存空间中的缓存页既有空闲的,也有被使用的,为了能够快速找到空闲的缓存页,可以使用链表结构。MySQL将空闲缓存页的控制块作为链表的节点,这个链表称为 Free 链表(空闲链表),如图

在这里插入图片描述

  • Free 链表上除了有控制块,还有一个头节点,该头节点包含链表的头节点地址尾节点地址,以及当前链表中节点的数量等信息,头节点是一块单独申请的内存空间(约占40字节),并不在Buffer Pool的连续内存空间里
  • Free 链表节点是一个一个的控制块,而每个控制块包含着对应缓存页的地址,所以相当于 Free 链表节点都对应一个空闲的缓存页
  • 每个控制块块里都有两个指针分别是:(pre)指向上一个节点,(next)指向下一个节点;而且还有一个(clt)数据页地址

buffer pool在寻找空闲数据页的时候直接用free链表可以直接找到。只要有一页数据空闲出来之后,直接把该数据页的地址追加到free链表即可。反之每当需要从磁盘中加载一个页到 Buffer Pool 中时,就从 Free链表中取一个空闲的缓存页,并且把该缓存页对应的控制块的信息填上,然后把该缓存页对应的控制块从 Free 链表中移除

2.3.3 如何管理脏页

设计 Buffer Pool 除了能提高读性能,还能提高写性能,也就是更新数据的时候,不需要每次都要写入磁盘,而是将 Buffer Pool 对应的缓存页标记为脏页,然后再由后台线程将脏页写入到磁盘。

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

在这里插入图片描述
有了 Flush 链表后,后台线程就可以遍历 Flush 链表,将脏页写入到磁盘。

2.3.4 如何提高缓存命中率?

Buffer Pool 的大小是有限的,对于一些频繁访问的数据我们希望可以一直留在 Buffer Pool 中,而一些很少访问的数据希望可以在某些时机可以淘汰掉,从而保证 Buffer Pool 不会因为满了而导致无法再缓存新的数据,同时还能保证常用数据留在 Buffer Pool 中。要实现这个,最容易想到的就是 LRU(Least recently used)算法

该算法的思路是,链表头部的节点是最近使用的,而链表末尾的节点是最久没被使用的。那么,当空间不够了,就淘汰最久没被使用的节点,从而腾出空间。

简单的 LRU 算法的实现思路是这样的:

  • 当访问的页在 Buffer Pool 里,就直接把该页对应的 LRU 链表节点移动到链表的头部。
  • 当访问的页不在 Buffer Pool里,除了要把页放入到 LRU 链表的头部,还要淘汰 LRU 链表末尾的节点。

LRU 的实现过程如下:

在这里插入图片描述

假如我们要访问3号页数据,因为3号页在Buffer Pool 中,所以会把3号页移动到头部即可

在这里插入图片描述
假如我们要访问6号页数据,但是6号页不在Buffer Pool 中,所以会淘汰了5号页,然后在头部加入6号页数据

在这里插入图片描述

到这里我们可以知道,Buffer Pool 里有三种页和链表来管理数据

  • Free Page(空闲页),表示此页未被使用,位于 Free 链表;
  • Clean Page(干净页),表示此页已被使用,但是页面未发生修改,位于LRU 链表。
  • Dirty Page(脏页),表示此页已被使用且已经被修改,其数据和磁盘上的数据已经不一致。当脏页上的数据写入磁盘后,内存数据和磁盘数据一致,那么该页就变成了干净页。脏页同时存在于 LRU 链表和 Flush 链表。

但是,MYSQL并没有使用简单的LRU算法,因为它无法解决下面问题:

  • 预读失效
  • Buffer Pool 污染

2.3.5 预读失效

先来说说 MySQL 的预读机制

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

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

如果使用简单的 LRU 算法,就会把预读页放到 LRU 链表头部,而当 Buffer Pool空间不够的时候,还需要把末尾的页淘汰掉。如果这些预读页如果一直不会被访问到,就会出现一个很奇怪的问题,不会被访问的预读页却占用了 LRU 链表前排的位置,而末尾淘汰的页,可能是频繁访问的页,这样就大大降低了缓存命中率。

怎么避免预读失效带来影响?

要避免预读失效带来影响,最好就是让预读的页停留在 Buffer Pool 里的时间要尽可能的短,让真正被访问的页才移动到 LRU 链表的头部,从而保证真正被读取的热数据留在 Buffer Pool 里的时间尽可能长。

MySQL 是这样做的,它改进了 LRU 算法,将 LRU 划分了 2 个区域:old 区域young 区域

young 区域在 LRU 链表的前半部分,old 区域则是在后半部分,如图

在这里插入图片描述

old 区域占整个 LRU 链表长度的比例可以通 innodb_old_blocks_pc 变量来设置,默认是 37

mysql> show variables like '%innodb_old_blocks_pc%';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_old_blocks_pct | 37    |
+-----------------------+-------+
1 row in set (0.01 sec)

代表整个 LRU 链表中 young 区域与 old 区域比例是 63:37,划分这两个区域后,预读的页就只需要加入到 old 区域的头部,当页被真正访问的时候,才将页插入 young 区域的头部。如果预读的页一直没有被访问,就会从 old 区域移除,这样就不会影响 young 区域中的热点数据。这个变量是可以根据我们实际情况修改

mysql> set persist innodb_old_blocks_pct = 40;
Query OK, 0 rows affected (0.00 sec)

举个例子

  • 假设有一个长度为 10 的 LRU 链表,其中 young 区域占比 70 %,old 区域占比 30%。如下

在这里插入图片描述

  • 假如我们有两个11和12号页被预读了,这个页号会被插入到old区域头部,而old区域9和10号页给淘汰,如果9和10号页一直没有被访问到,那么就不会占用young区域的位置,而且会给young区域的数据更早被淘汰

在这里插入图片描述

  • 如果11号页被预读后,立刻被访问了,那么就会将它插入到 young 区域的头部,young 区域末尾的页(7号),会被挤到 old 区域,作为 old 区域的头部,这个过程并不会有页被淘汰。

在这里插入图片描述

2.3.6 Buffer Pool污染

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

注意, Buffer Pool 污染并不只是查询语句查询出了大量的数据才出现的问题,即使查询出来的结果集很小,也会造成 Buffer Pool 污染。比如,在一个数据量非常大的表,执行了这条语句:select * from t_user where name like '%a%'可能这个查询出来的结果就几条记录,但是由于这条语句会发生索引失效,所以这个查询过程是全表扫描的,接着会发生如下的过程:

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

怎么解决出现 Buffer Pool 污染而导致缓存命中率下降的问题?

像前面这种全表扫描的查询,很多缓冲页其实只会被访问一次,但是它却只因为被访问了一次而进入到 young 区域,从而导致热点数据被替换了。

LRU 链表中 young 区域就是热点数据,只要我们提高进入到 young 区域的门槛,就能有效地保证 young 区域里的热点数据不会被替换掉。

MySQL 是这样做的,进入到 young 区域条件增加了一个停留在 old 区域的时间判断。

具体是这样做的,在对某个处在 old 区域的缓存页进行第一次访问时,就在它对应的控制块中记录下来这个访问时间:

  • 如果后续的访问时间与第一次访问的时间在某个时间间隔内,那么该缓存页就不会被从 old 区域移动到 young 区域的头部;
  • 如果后续的访问时间与第一次访问的时间不在某个时间间隔内,那么该缓存页移动到 young 区域的头部;

这个间隔时间是由 innodb_old_blocks_time 控制的,默认1000毫秒,也就是1秒

mysql> show variables like '%innodb_old_blocks_time%';
+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| innodb_old_blocks_time | 1000  |
+------------------------+-------+
1 row in set (0.01 sec)

也就说,只有同时满足被访问在 old 区域停留时间超过 1 秒两个条件,才会被插入到 young 区域头部,这样就解决了 Buffer Pool 污染的问题 ,这个变量是可以根据我们实际情况进行修改

mysql> set persist innodb_old_blocks_time  = 2000;
Query OK, 0 rows affected (0.01 sec)

2.3.7 脏页什么时候会被刷入磁盘?

引入了 Buffer Pool 后,当修改数据时,首先是修改 Buffer Pool 中数据所在的页,然后将其页设置为脏页,但是磁盘中还是原数据。

因此,脏页需要被刷入磁盘,保证缓存和磁盘数据一致,但是若每次修改数据都刷入磁盘,则性能会很差,因此一般都会在一定时机进行批量刷盘。

可能大家担心,如果在脏页还没有来得及刷入到磁盘时,MySQL 宕机了,不就丢失数据了吗?

这个不用担心,InnoDB 的更新操作采用的是 Write Ahead Log 策略,即先写日志,再写入磁盘,通过 redo log 日志让 MySQL 拥有了崩溃恢复能力。

下面几种情况会触发脏页的刷新:

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

在我们开启了慢 SQL 监控后,如果你发现偶尔会出现一些用时稍长的 SQL,这可能是因为脏页在刷新到磁盘时可能会给数据库带来性能开销,导致数据库操作抖动。如果间断出现这种现象,就需要调大 Buffer Pool 空间或 redo log 日志的大小。后期会有讲解

2.4 缓冲池的高并发

如果 InnoDB 存储引擎只有一个 Buffer Pool,当高并发时,多个请求进来,那么为了保证数据的一致性(缓存页、free 链表、flush 链表、lru 链表等多种操作),必须得给缓冲池加锁了,每一时刻只能有一个请求获得锁去操作 Buffer Pool,其他请求只能排队等待锁释放,那么此时 MySQL 的性能是有多么的低。

我们是可以通过修改变量innodb_buffer_pool_instances 给 MySQL 设置多个 Buffer Pool 来提升 MySQL 的并发能力。

innodb_buffer_pool_instances 是一个持久化只读系统变量,需要授予persist_ro_variables_admin(启用持久化只读系统变量)和system_variables_admin(启用修改或保留全局系统变量)的权限,

mysql> set persist_only innodb_buffer_pool_instances=4;
Query OK, 0 rows affected (0.01 sec)

修改完成后,我们需要重启mysql

mysql> show variables like '%innodb_buffer_pool_instances%';
+------------------------------+-------+
| Variable_name                | Value |
+------------------------------+-------+
| innodb_buffer_pool_instances | 4     |
+------------------------------+-------+
1 row in set (0.02 sec)

每个 Buffer Pool 负责管理着自己的控制块和缓存页,有自己独立一套 free 链表、flush 链表和 LRU链表

假设给 Buffer Pool 调整到 16 G,就是说变量innodb_buffer_pool_size 改为 17179869184,此时,MySQL 会为 Buffer Pool 申请一块大小为16G 的连续内存,然后分成 4块,接着将每一个 Buffer Pool 的数据都复制到对应的内存块里,最后再清空之前的内存区域。那这是相当耗费时间的操作

为了解决上面的问题,Buffer Pool 引入一个机制:chunk 机制

  • 每个 Buffer Pool 其实是由多个 chunk 组成的。每个 chunk 的大小由参数 innodb_buffer_pool_chunk_size 控制,默认值是 128M。
mysql> show variables like '%innodb_buffer_pool_chunk_size%';
+-------------------------------+-----------+
| Variable_name                 | Value     |
+-------------------------------+-----------+
| innodb_buffer_pool_chunk_size | 134217728 |
+-------------------------------+-----------+
1 row in set (0.01 sec)

innodb_buffer_pool_chunk_size 这个变量如同innodb_buffer_pool_instances 一样,是一个持久化只读系统变量,修改完成后需要重启MySQL

mysql> set persist_only innodb_buffer_pool_chunk_size  = 132417728;
Query OK, 0 rows affected (0.00 sec)
  • 每个 chunk 就是一系列的描述数据块和对应的缓存页。
  • 每个 Buffer Pool 里的所有 chunk 共享一套 free、flush、lru 链表。

在这里插入图片描述

得益于 chunk 机制,通过增加 Buffer Pool 的chunk个数就能避免了上面说到的问题。当扩大 Buffer Pool 内存时,不再需要全部数据进行复制和粘贴,而是在原本的基础上进行增减内存。

下面举个例子,介绍一下 chunk 机制下,Buffer Pool 是如何动态调整大小的:

  • 调整前 Buffer Pool 的总大小为 8G,调整后的 Buffer Pool 大小为 16 G。
  • 由于 Buffer Pool 的实例数是不可以变的,所以是每个 Buffer Pool 增加 2G 的大小,此时只要给每个 Buffer Pool 申请 (2048M/128M)个chunk就行了,但是要注意的是,新增的每个 chunk 都是连续的128M内存。

缓冲池大小必须始终等于或者是innodb_buffer_pool_chunk_size * innodb_buffer_pool_instances的倍数。如果将缓冲池大小更改为不等于或等于innodb_buffer_pool_chunk_size **innodb_buffer_pool_instances的倍数的值,
则缓冲池大小将自动调整为等于或者是innodb_buffer_pool_chunk_size * innodb_buffer_pool_instances的倍数的值

2.5 缓冲池数据预热(了解)

我们关闭数据库的时候,想将缓冲池中的数据保存到ib_Buffer_pool中,可以调整如下变量
innodb_buffer_pool_dump_pct:指定每个缓冲池最近使用的页面读取和转储的百分比。 范围是1到100。默认值是25。例如,如果有4个缓冲池,每个缓冲池有100个page,并且innodb_buffer_pool_dump_pct设置为25,则dump每个缓冲池中最近使用的25个page。
innodb_buffer_pool_dump_at_shutdown:默认启用。指定在MySQL服务器关闭时是否记录在InnoDB缓冲池中缓存的页面,以便在下次重新启动时缩短预热过程。
innodb_buffer_pool_load_at_startup:默认启用。指定在MySQL服务器启动时,InnoDB缓冲池通过加载之前保存的相同页面自动预热。 通常与innodb_buffer_pool_dump_at_shutdown结合使用

2.6 缓冲池的案例

2.6.1 大量的全表扫描

如果在业务中做了大量的全表扫描,那么你就可以将innodb_old_blocks_pct设置减小,增大innodb_old_blocks_time的时间,不让这些无用的查询数据进入old区域,尽量不让缓存再young 区域的有用的数据被立即刷掉。(这也是治标的方法,大量全表扫描就要优化sql和表索引结构了)

mysql> set persist innodb_old_blocks_time=4000;
Query OK, 0 rows affected (0.00 sec)

mysql> set persist innodb_old_blocks_pct=20;
Query OK, 0 rows affected (0.01 sec)

2.6.2 没有大量的全表扫描

如果在业务中没有做大量的全表扫描,那么你就可以将innodb_old_blocks_pct增大,减小innodb_old_blocks_time的时间,让有用的查询缓存数据尽量缓存在innodb_buffer_pool_size中,减小磁盘io,提高性能。

mysql> set persist innodb_old_blocks_time=1000;
Query OK, 0 rows affected (0.00 sec)

mysql> set persist innodb_old_blocks_pct=37;
Query OK, 0 rows affected (0.01 sec)

在这里插入图片描述

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

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

相关文章

【Linux从入门到精通】Linux常用基础指令(下)

本篇文章接上篇文章(【Linux从入门到精通】Linux常用基础指令(上)、【Linux从入门到精通】Linux常用基础指令(中))进行详解。本章的指令相对没有那么常用,难度相对适中。同时也讲述了几个热键。…

编程式导航路由跳转到当前路由(参数不变),多次执行会抛出NavigatorDuplicated的禁告错误?

重写push与replace方法 编程式导航路由跳转到当前路由(参数不变),多次执行会抛出NavigatorDuplicated的禁告错误? 路由跳转有俩种形式:声明式导航,编程式导航 声明式导航没有这类问题的,因为…

【精华】WiderPerson数据集介绍及标签转换(YOLO格式)

文章目录 &#xff08;1&#xff09;WiderPerson数据集详情<1> 应用项目<2> 数据集地址<3> 归属单位<4> 详细介绍<5> 数据下载及格式介绍 &#xff08;2&#xff09;WiderPerson转YOLO格式<1> 文件夹结构<2> 数据可视化<3> YO…

全国计算机等级三级网络技术试卷详解(三)

请点击↑关注、收藏&#xff0c;本博客免费为你获取精彩知识分享&#xff01;有惊喜哟&#xff01;&#xff01; 1.下列关于RPR技术的描述中&#xff0c;错误的是&#xff08;&#xff09;。 A) RPR与FDDI一样使用双环结构 B) 在RPR环中&#xff0c;源节点向目的节点成功发出…

JVM(Java虚拟机)

目录 1.JVM 简介 2. JVM 运行时数据区 2.1程序计数器 2.栈 3.堆 4.方法区 3.类加载 1.loading 2.linking 1.验证 2.准备 3.解析 3.Initializing 4.双亲委派模型 5.JVM垃圾回收机制 1.劣势 2.回收什么 3.垃圾回收具体怎么回收 1.找垃圾 方法: 问题: 2.释放…

4月JAVA面试太难,吃透这份JAVA架构面试笔记后,成功涨到30K

昨天跟一位高级架构师的前辈聊天时&#xff0c;聊到今年的面试。有两个感受&#xff0c;一个是今年面邀的次数比往年要低不少&#xff0c;再一个就是很多面试者准备明显不足。不少候选人能力其实不差&#xff0c;进入团队干活后达到期望不难&#xff0c;但由于没准备或不会表达…

快速响应 智慧应急|大势智慧亮相第三届武汉国际安全应急博览会

4月26日至4月28日&#xff0c;第三届武汉国际安全应急博览会&#xff08;后简称“应博会”&#xff09;在湖北武汉顺利举办。本次展会&#xff0c;大势智慧以实时三维重建能力为核心&#xff0c;提供各类应急场景的技术支撑&#xff0c;助力应急处置和救援等方面的应用。 展会…

基于AI技术的智能考试系统设计与实现(论文+源码)_kaic

摘 要 随着当今世界互联网信息技术的飞速发展&#xff0c;互联网在人们生活中的应用越来越广泛&#xff0c;在线考试成为选拔人才的重要方法。实现一个基于AI技术的智能考试系统&#xff0c;该系统采用Java编程语言实现。通过使用自然语言处理技术和机器学习算法&#xff0c;该…

【C++】入门

目录 1. 什么是C2. 命名空间2.1 命名空间的定义2.2 命名空间的使用 3. 输入和输出4. 缺省参数4.1 概念4.2 分类 5. 函数重载5.1 函数重载概念5.2 为什么支持函数重载 6. 引用6.1 概念6.2 特性6.3 常引用6.4 指针与引用的区别 7. 内联函数7.1 特性 1. 什么是C C语言是结构化和模…

【c语言】五大内存区域 | 堆区详解

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 给大家跳段街舞感谢支持&#xff01;ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ…

Paimon: Streaming data lake 数据湖项目的后起之秀

什么是Paimon? Paimon的官网介绍是&#xff1a;Streaming data lake platform with high-speed data ingestion, changelog tracking and efficient real-time analytics. Paimon 是流数据湖平台&#xff0c;具有高速数据摄取、变更日志跟踪和高效的实时分析能力 数据湖是大…

unity什么是曲线动画?

介绍 unity什么是曲线动画&#xff1f; 在Unity中&#xff0c;曲线动画&#xff08;Curve Animation&#xff09;是一种基于曲线的动画系统&#xff0c;它允许你通过在时间轴上编辑曲线来控制游戏对象的某个属性在时间上的变化。曲线动画可以用于很多方面&#xff0c;比如控制…

Linux套接字编程-2

在上一篇博客中&#xff0c;我们先对套接字编程的内容进行了一个简单涵盖&#xff0c;并详细陈述了UDP协议内容。本篇我们承接上文&#xff0c;讲述完UDP后&#xff0c;我们来讲解TCP。 目录 1.TCP协议 1.1通信两端流程 1.1.1服务端流程 1.1.2客户端流程 1.2套接字相关操…

LeCun、田渊栋参与撰写,70页「自监督学习」大全

来源 | 机器之心 微信号&#xff1a;almosthuman2014 「关于自监督学习&#xff0c;你想知道但又不敢问的一切都在这里了。」图灵奖得主、Meta 人工智能首席科学家 Yann LeCun 刚刚发了这样一则推文。 在推文中&#xff0c;LeCun 介绍了他和 Meta 人工智能研究院研究员、研究经…

数据结构学习记录——判断是否为同一颗二叉搜索树(题意理解、求解思路、程序搭建框架、具体函数的实现)

目录 题意理解 问题 描述 输入样例 输出样例 求解思路 建两棵二叉树 不建树 建一棵树 搜索树表示 程序框架搭建 如何建搜索树 如何判别 方法 查找函数 判断函数 其他函数 题意理解 给定一个插入序列就可以唯一确定一颗二叉搜索树。 但是&#xff0c;一颗给定…

libigl添加Viewer Menu时出现imgui相关的错误:无法打开包括文件: “imgui.h”: No such file or directory

libigl添加如下图所示的Viewer Menu时&#xff0c;出现了“无法打开包括文件: “imgui.h”: No such file or directory”的错误 很显然是libigl内嵌的imgui出了问题 从项目路径libigl-example-project-main\out\build\x64-Release\_deps\libigl-src\include\igl\opengl\glfw\…

【谷粒商城之CompletableFuture异步编排】

本笔记内容为尚硅谷谷粒商城CompletableFuture异步编排部分 目录 一、线程回顾 1 、初始化线程的 4 种方式 2.、线程池的七大参数 运行流程&#xff1a; 3、常见的4种线程池 4、开发中为什么使用线程池 二、CompletableFuture 异步编排 业务场景 1、创建异步对象 …

无线化超轻薄,香港城市大学体感反馈贴片WeTac

此前&#xff0c;青亭网曾报道香港城市大学与腾讯Robotics X Lab合作研发的低电压体感方案&#xff0c;原理是通过微电流刺激来模拟触觉&#xff0c;可模拟微小物体的体感。近期&#xff0c;香港城市大学的一组科研人员也公布了一项类似的方案&#xff1a;WeTac&#xff0c;该方…

轻松上手:使用VSCode调试Python模块级代码的完整教程

安装VSCode&#xff1a;请确保已经安装了Visual Studio Code。安装Python插件&#xff1a;在VSCode中&#xff0c;转到Extensions视图 (View -> Extensions) 并搜索"Python"。找到由Microsoft提供的插件并点击安装。重启VSCode以确保插件安装正确。准备项目&#…

边听歌边充电LDR6028+LDR9201既能充电又能OTG方案

随着type-c接口的普及&#xff0c;市面上的手机&#xff0c;平板&#xff0c;笔电逐渐都采用了type-c接口&#xff0c;设备为了不断的追求更轻薄的机身和防水要求慢慢的取消了一些影响手机外观完整性的接口&#xff0c;比如3.5mm耳机孔。 有线耳机用户一般会选择使用C口转3.5m…