14.5.1 缓冲池
缓冲池是主存储器中的一个区域,InnoDB
在访问 table 和索引数据时会对其进行缓存。缓冲池允许直接从内存中处理经常使用的数据,从而加快了处理速度。在专用服务器上,通常将多达 80%的物理内存分配给缓冲池。
为了提高大容量读取操作的效率,缓冲池被分为pages,它们可以潜在地容纳多行。为了提高缓存 Management 的效率,缓冲池被实现为页面的链接列 table。使用LRU算法的变体将很少使用的数据从缓存中老化掉。
知道如何利用缓冲池将经常访问的数据保留在内存中是 MySQL 优化的重要方面。
缓冲池 LRU 算法
缓冲池使用最近最少使用(LRU)算法的变体作为列 table 进行 Management。当需要空间以将新页面添加到缓冲池时,将驱逐最近使用最少的页面,并将新页面添加到列 table 的中间。此中点插入策略将列 table 视为两个子列 table:
-
最前面是最近访问过的新(“年轻”)页面的子列 table
-
在末尾,是最近访问过的旧页面的子列 table
图 14.2 缓冲池列 table
该算法将大量页面保留在新的子列 table 中。旧的子列 table 包含较少使用的页面。这些页面是eviction的候选页面。
默认情况下,该算法的操作如下:
-
缓冲池的 3/8 专用于旧的子列 table。
-
列 table 的中点是新子列 table 的尾部与旧子列 table 的头相交的边界。
-
当
InnoDB
将页面读入缓冲池时,它最初将其插入中点(旧子列 table 的头部)。可以读取页面,因为它是用户启动的操作(例如 SQL 查询)所必需的,或者是InnoDB
自动执行的read-ahead操作的一部分。 -
访问旧子列 table 中的页面会使其“年轻”,并将其移至新子列 table 的开头。如果由于用户启动的操作而需要读取页面,则将立即进行首次访问,并使页面年轻。如果由于预读操作而读取了该页面,则第一次访问不会立即发生,并且在退出该页面之前可能根本不会发生。
-
随着数据库的运行,通过移至列 table 的末尾,未访问缓冲池中的页面“变旧”。新的和旧的子列 table 中的页面都会随着其他页面的更新而老化。随着将页面插入中点,旧子列 table 中的页面也会老化。最终,未使用的页面到达旧子列 table 的尾部并被逐出。
默认情况下,查询读取的页面会立即移入新的子列 table,这意味着它们在缓冲池中停留的时间更长。例如,针对mysqldump操作或不具有WHERE
子句的SELECT
语句执行的 table 扫描可以将大量数据带入缓冲池,并逐出相同数量的旧数据,即使不再使用新数据也是如此。 。同样,由预读后台线程加载且仅访问一次的页面将移至新列 table 的开头。这些情况可能会将常用页面推送到旧的子列 table,在此它们将被逐出。有关优化此行为的信息,请参见第 14.8.3.3 节“使缓冲池扫描具有抵抗力”和第 14.8.3.4 节“配置 InnoDB 缓冲池预取(预读)”。
InnoDB
Standard Monitor 的输出在BUFFER POOL AND MEMORY
部分中包含几个与缓冲池 LRU 算法的操作有关的字段。有关详细信息,请参见使用 InnoDB 标准监视器监视缓冲池。
缓冲池配置
您可以配置缓冲池的各个方面以提高性能。
-
理想情况下,您可以将缓冲池的大小设置为与实际一样大的值,从而为服务器上的其他进程留出足够的内存以运行而不会进行过多的分页。缓冲池越大,则
InnoDB
就像内存数据库一样,从磁盘读取一次数据,然后在后续读取过程中从内存访问数据。参见第 14.8.3.1 节“配置 InnoDB 缓冲池大小”。 -
在具有足够内存的 64 位系统上,可以将缓冲池分成多个部分,以最大程度地减少并发操作之间的内存结构争用。有关详细信息,请参见第 14.8.3.2 节“配置多个缓冲池实例”。
-
您可以将频繁访问的数据保留在内存中,而不管操作中突然出现的活动高峰如何将大量不经常访问的数据带入缓冲池中。有关详细信息,请参见第 14.8.3.3 节“使缓冲池扫描具有抵抗力”。
-
您可以控制何时以及如何执行预读请求,以异步方式将页面预取到缓冲池中,从而预期很快将需要这些页面。有关详细信息,请参见第 14.8.3.4 节“配置 InnoDB 缓冲池预取(预读)”。
-
您可以控制何时进行后台冲洗,以及是否根据工作负荷动态调整冲洗速率。有关详细信息,请参见第 14.8.3.5 节“配置缓冲池刷新”。
-
您可以配置
InnoDB
保留当前缓冲池状态的方式,以避免服务器重启后的漫长预热时间。有关详细信息,请参见第 14.8.3.6 节“保存和恢复缓冲池状态”。
使用 InnoDB 标准监视器监视缓冲池
可以使用显示引擎的 INNODB 状态进行访问的InnoDB
Standard Monitor 输出提供有关缓冲池操作的度量。缓冲池度量标准位于InnoDB
Standard Monitor 输出的BUFFER POOL AND MEMORY
部分中,并且看起来类似于以下内容:
----------------------
BUFFER POOL AND MEMORY
----------------------
Total large memory allocated 2198863872
Dictionary memory allocated 776332
Buffer pool size 131072
Free buffers 124908
Database pages 5720
Old database pages 2071
Modified db pages 910
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 4, not young 0
0.10 youngs/s, 0.00 non-youngs/s
Pages read 197, created 5523, written 5060
0.00 reads/s, 190.89 creates/s, 244.94 writes/s
Buffer pool hit rate 1000 / 1000, young-making rate 0 / 1000 not
0 / 1000
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read
ahead 0.00/s
LRU len: 5720, unzip_LRU len: 0
I/O sum[0]:cur[0], unzip sum[0]:cur[0]
下 table 描述了InnoDB
Standard Monitor 报告的缓冲池 Metrics。
Note
InnoDB
Standard Monitor 输出中提供的每秒平均值基于自上次打印InnoDB
Standard Monitor 输出以来经过的时间。
table14.2 InnoDB 缓冲池 Metrics
Name | Description |
---|---|
分配的总内存 | 为缓冲池分配的总内存(以字节为单位)。 |
分配的字典内存 | 为InnoDB 数据字典分配的总内存,以字节为单位。 |
缓冲池大小 | 分配给缓冲池的页面总大小。 |
Free buffers | 缓冲池空闲列 table 的页面总大小。 |
Database pages | 缓冲池 LRU 列 table 的页面总大小。 |
旧数据库页面 | 缓冲池旧 LRU 子列 table 的页面总大小。 |
修改的数据库页面 | 缓冲池中当前修改的页面数。 |
Pending reads | await 读入缓冲池的缓冲池页面数。 |
待写 LRU | 从 LRU 列 table 的底部开始写入的缓冲池中的旧脏页数。 |
await 写入刷新列 table | 检查点期间要刷新的缓冲池页面数。 |
待写单页 | 缓冲池中暂挂的独立页面写入数。 |
使页面年轻化 | 在缓冲池 LRU 列 table 中变年轻的页面总数(移至“新”页面的子列 table 的开头)。 |
页面不年轻 | 缓冲池 LRU 列 table 中没有年轻的页面总数(保留在“旧”子列 table 中但没有年轻的页面)。 |
youngs/s | 每秒平均访问缓冲池 LRU 列 table 中的旧页面所导致的页面年轻。有关更多信息,请参见此 table 后面的 Comments。 |
non-youngs/s | 每秒平均访问缓冲池 LRU 列 table 中的旧页面导致的页面不年轻。有关更多信息,请参见此 table 后面的 Comments。 |
Pages read | 从缓冲池读取的页面总数。 |
Pages created | 在缓冲池中创建的页面总数。 |
Pages written | 从缓冲池写入的页面总数。 |
reads/s | 每秒平均每秒读取的缓冲池页面数。 |
creates/s | 每秒平均创建的缓冲池页面的每秒数量。 |
writes/s | 每秒平均缓冲池页面写入数。 |
缓冲池命中率 | 从缓冲池内存与磁盘存储读取的页面的缓冲池页面命中率。 |
young-making rate | 页面访问的平均命中率使页面更年轻。有关更多信息,请参见此 table 后面的 Comments。 |
不(成年率) | 页面访问未使页面变年轻的平均命中率。有关更多信息,请参见此 table 后面的 Comments。 |
预读页面 | 预读操作的每秒平均数。 |
被逐出的页面无权访问 | 每秒从缓冲池访问而未访问的页面的平均值。 |
随机预读 | 随机预读操作的每秒平均数。 |
LRU len | 缓冲池 LRU 列 table 的页面总大小。 |
unzip_LRU len | 缓冲池 unzip_LRU 列 table 的页面总大小。 |
I/O sum | 最近 50 秒内访问的缓冲池 LRU 列 table 页面的总数。 |
I/O cur | 已访问的缓冲池 LRU 列 table 页面的总数。 |
I/O 解压缩总和 | 已访问的缓冲池 unzip_LRU 列 table 页面的总数。 |
I/O 解压缩 | 已访问的缓冲池 unzip_LRU 列 table 页面的总数。 |
Notes :
-
youngs/s
Metrics 仅适用于旧页面。它基于对页面的访问次数而不是页面数。可以对给定页面进行多次访问,所有访问都计入在内。如果没有大扫描时看到的youngs/s
值很低,则可能需要减少延迟时间或增加用于旧子列 table 的缓冲池百分比。增加百分比会使旧的子列 table 变大,因此该子列 table 中的页面需要更长的时间才能移到尾部,这增加了再次访问这些页面并使它们变年轻的可能性。 -
non-youngs/s
Metrics 仅适用于旧页面。它基于对页面的访问次数而不是页面数。可以对给定页面进行多次访问,所有访问都计入在内。如果执行大型 table 扫描时看不到较高的non-youngs/s
值(和较高的youngs/s
值),请增加延迟值。 -
young-making
计费用于访问所有缓冲池页面,而不仅仅是访问旧子列 table 中的页面。young-making
速率和not
速率通常不会加总到整个缓冲池命中率。旧子列 table 中的页面命中会导致页面移动到新的子列 table,但是新子列 table 中的页面命中只会导致页面与列 table 的头部保持一定距离时才移动到列 table 的头部。 -
not (young-making rate)
是由于未满足innodb_old_blocks_time所定义的延迟,或者由于新子列 table 中的页面点击未导致页面移动到头部而导致页面访问未使页面变年轻的平均点击率。此速率说明了对所有缓冲池页面的访问,而不仅仅是访问旧子列 table 中的页面。
缓冲池服务器状态变量和INNODB_BUFFER_POOL_STATStable 提供了与InnoDB
Standard Monitor 输出中许多相同的缓冲池度量标准。有关更多信息,请参见示例 14.10“查询 INNODB_BUFFER_POOL_STATStable”。