缓冲池是主内存中的一块区域,InnoDB
在访问表和索引数据时将其缓存到该区域。缓冲池允许直接从内存访问频繁使用的数据,从而加快处理速度。在专用服务器上,通常将高达 80% 的物理内存分配给缓冲池。
为了提高大量读取操作的效率,缓冲池被划分为页,这些页可能包含多个行。为了提高缓存管理的效率,缓冲池被实现为页的链表;很少使用的数据使用最少最近使用 (LRU) 算法的变体从缓存中老化。
了解如何利用缓冲池将频繁访问的数据保留在内存中是 MySQL 调整的一个重要方面。
缓冲池使用 LRU 算法的变体作为列表进行管理。当需要空间将新页面添加到缓冲池时,最少最近使用的页面将被逐出,新页面将被添加到列表的中间。这种中间插入策略将列表视为两个子列表
在头部,一个新 (“年轻”) 页面的子列表,这些页面最近被访问过
在尾部,一个旧页面的子列表,这些页面最近访问的次数较少
该算法将频繁使用的页面保留在新子列表中。旧子列表包含使用频率较低的页面;这些页面是驱逐的候选者。
默认情况下,该算法的工作方式如下
缓冲池的 3/8 用于旧子列表。
列表的中点是新子列表的尾部与旧子列表的头部相遇的边界。
当
InnoDB
将页面读入缓冲池时,它最初会将其插入中点(旧子列表的头部)。页面可能被读取是因为它需要用于用户发起的操作(例如 SQL 查询),或者作为InnoDB
自动执行的读提前操作的一部分。访问旧子列表中的页面会使其“年轻”,将其移到新子列表的头部。如果页面是在用户发起的操作需要时读取的,则第一次访问会立即发生,并且页面会变得年轻。如果页面是由于读提前操作而读取的,则第一次访问不会立即发生,并且可能根本不会发生在页面被驱逐之前。
随着数据库的运行,缓冲池中未被访问的页面会“老化”,向列表的尾部移动。新旧子列表中的页面随着其他页面变为新页面而老化。旧子列表中的页面也随着页面插入到中点而老化。最终,一个未被使用的页面会到达旧子列表的尾部,并被驱逐。
默认情况下,查询读取的页面会立即移到新子列表,这意味着它们会在缓冲池中停留更长时间。例如,为mysqldump 操作或没有WHERE
子句的SELECT
语句执行的表扫描会将大量数据带入缓冲池,并驱逐等量的旧数据,即使新数据永远不再使用。同样,由读提前后台线程加载且只访问一次的页面也会被移动到新列表的头部。这些情况可能会将频繁使用的页面推送到旧子列表,在那里它们会变得容易被驱逐。有关优化此行为的信息,请参见第 17.8.3.3 节,“使缓冲池扫描具有抗性” 和第 17.8.3.4 节,“配置 InnoDB 缓冲池预取(读提前)”。
InnoDB
标准监控输出在 BUFFER POOL AND MEMORY
部分包含多个字段,这些字段与缓冲池 LRU 算法的操作相关。有关详细信息,请参见 使用 InnoDB 标准监控器监控缓冲池。
您可以配置缓冲池的各个方面以提高性能。
理想情况下,您将缓冲池的大小设置为尽可能大的值,为服务器上的其他进程留出足够的内存,以避免过度分页。缓冲池越大,
InnoDB
越像一个内存数据库,它只从磁盘读取一次数据,然后在后续读取中从内存访问数据。请参见 第 17.8.3.1 节,“配置 InnoDB 缓冲池大小”。在具有足够内存的 64 位系统上,您可以将缓冲池拆分为多个部分,以最大程度地减少并发操作之间对内存结构的争用。有关详细信息,请参见 第 17.8.3.2 节,“配置多个缓冲池实例”。
您可以将经常访问的数据保留在内存中,而不管操作突然出现的峰值,这些操作会将大量不常访问的数据带入缓冲池。有关详细信息,请参见 第 17.8.3.3 节,“使缓冲池扫描更具抵抗力”。
您可以控制何时以及如何执行预读请求,以便在预期需要时异步预取页面到缓冲池。有关详细信息,请参见 第 17.8.3.4 节,“配置 InnoDB 缓冲池预取(预读)”。
您可以控制何时发生后台刷新以及是否根据工作负载动态调整刷新速率。有关详细信息,请参见 第 17.8.3.5 节,“配置缓冲池刷新”。
您可以配置
InnoDB
如何保留当前缓冲池状态以避免在服务器重新启动后出现漫长的预热期。有关详细信息,请参见 第 17.8.3.6 节,“保存和恢复缓冲池状态”。
InnoDB
标准监控输出(可以使用 SHOW ENGINE INNODB STATUS
访问)提供有关缓冲池操作的指标。缓冲池指标位于 InnoDB
标准监控输出的 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]
下表描述了 InnoDB
标准监控器报告的缓冲池指标。
InnoDB
标准监控输出中提供的每秒平均值基于自上次打印 InnoDB
标准监控输出以来的经过时间。
表 17.2 InnoDB 缓冲池指标
名称 | 描述 |
---|---|
分配的总内存 | 为缓冲池分配的总内存(以字节为单位)。 |
分配的字典内存 | 为 InnoDB 数据字典分配的总内存(以字节为单位)。 |
缓冲池大小 | 分配给缓冲池的总页面大小。 |
空闲缓冲区 | 缓冲池空闲列表的总页面大小。 |
数据库页面 | 缓冲池 LRU 列表的总页面大小。 |
旧数据库页面 | 缓冲池旧 LRU 子列表的总页面大小。 |
修改的数据库页面 | 缓冲池中当前修改的页面数量。 |
待处理读取 | 等待读入缓冲池的缓冲池页面数量。 |
待处理写入 LRU | 缓冲池中要从 LRU 列表底部写入的旧脏页面数量。 |
待处理写入刷新列表 | 在检查点期间要刷新的缓冲池页面数量。 |
待处理写入单个页面 | 缓冲池中待处理的独立页面写入数量。 |
变为年轻的页面 | 缓冲池 LRU 列表中变为年轻的总页面数量(移动到 “新” 页面的子列表的头部)。 |
未变为年轻的页面 | 缓冲池 LRU 列表中未变为年轻的总页面数量(在未变为年轻的情况下保留在 “旧” 子列表中的页面)。 |
youngs/s | 缓冲池 LRU 列表中对旧页面的访问导致页面变为年轻的每秒平均次数。有关更多信息,请参见此表后的说明。 |
non-youngs/s | 缓冲池 LRU 列表中对旧页面的访问导致页面未变为年轻的每秒平均次数。有关更多信息,请参见此表后的说明。 |
读取的页面 | 从缓冲池读取的总页面数量。 |
创建的页面 | 缓冲池中创建的总页面数量。 |
写入的页面 | 从缓冲池写入的总页面数量。 |
reads/s | 每秒平均的缓冲池页面读取次数。 |
creates/s | 每秒创建的缓冲池页面的平均数量。 |
writes/s | 每秒写入的缓冲池页面的平均数量。 |
缓冲池命中率 | 从缓冲池读取的页面与从磁盘存储读取的页面的缓冲池页面命中率。 |
变为年轻的速率 | 页面访问导致页面变为年轻的平均命中率。有关更多信息,请参见此表后的说明。 |
未(变为年轻的速率) | 页面访问未导致页面变为年轻的平均命中率。有关更多信息,请参见此表后的说明。 |
预读的页面 | 预读操作的每秒平均次数。 |
未访问即被驱逐的页面 | 未从缓冲池访问即被驱逐的页面的每秒平均次数。 |
随机预读 | 随机预读操作的每秒平均次数。 |
LRU 长度 | 缓冲池 LRU 列表的总页面大小。 |
unzip_LRU 长度 | 缓冲池 unzip_LRU 列表的长度(以页面为单位)。 |
I/O 总计 | 访问的缓冲池 LRU 列表页面的总数。 |
I/O 当前 | 在当前时间间隔内访问的缓冲池 LRU 列表页面的总数。 |
I/O unzip 总计 | 解压缩的缓冲池 unzip_LRU 列表页面的总数。 |
I/O unzip 当前 | 在当前时间间隔内解压缩的缓冲池 unzip_LRU 列表页面的总数。 |
说明:
youngs/s
指标仅适用于旧页面。它基于页面访问次数。对于给定的页面,可以有多次访问,所有访问都将被计数。如果您在没有进行大型扫描的情况下看到非常低的youngs/s
值,请考虑减少延迟时间或增加用于旧子列表的缓冲池百分比。增加百分比会使旧子列表更大,因此该子列表中的页面需要更长时间才能移动到尾部,这会增加再次访问这些页面并使其变为年轻的可能性。请参见 第 17.8.3.3 节,“使缓冲池扫描更具抵抗力”。non-youngs/s
指标仅适用于旧页面。它基于页面访问次数。对于给定的页面,可以有多次访问,所有访问都将被计数。如果您在执行大型表扫描时(以及更高的youngs/s
值)没有看到更高的non-youngs/s
值,请增加延迟值。请参见 第 17.8.3.3 节,“使缓冲池扫描更具抵抗力”。young-making
速率考虑了所有缓冲池页面访问,而不仅仅是旧子列表中的页面访问。通常情况下,young-making
速率和not
速率不会加起来等于总的缓冲池命中率。旧子列表中的页面命中会导致页面移动到新子列表,但新子列表中的页面命中仅在它们距离头部一定距离时才会导致页面移动到列表的头部。not (young-making rate)
是页面访问未导致页面变为年轻的平均命中率,因为innodb_old_blocks_time
定义的延迟未达到,或者由于新子列表中的页面命中未导致页面移动到头部。此速率考虑了所有缓冲池页面访问,而不仅仅是旧子列表中的页面访问。
缓冲池 服务器状态变量 和 `INNODB_BUFFER_POOL_STATS` 表提供了与 InnoDB
标准监控输出中找到的许多相同的缓冲池指标。有关更多信息,请参见 示例 17.10,“查询 INNODB_BUFFER_POOL_STATS 表”。