缓冲池是主内存中的一块区域,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 | 每秒的缓冲池页面写入平均数量。 |
缓冲池命中率 | 从缓冲池读取的页面与从磁盘存储读取的页面的缓冲池页面命中率。 |
young-making 率 | 页面访问导致页面变新的平均命中率。有关更多信息,请参见本表后面的说明。 |
not (young-making 率) | 页面访问导致页面未变新的平均命中率。有关更多信息,请参见本表后面的说明。 |
已预读取的页面 | 预读操作的每秒平均值。 |
未经访问而被驱逐的页面 | 未经访问而从缓冲池驱逐的页面的每秒平均值。 |
随机预读 | 随机预读操作的每秒平均值。 |
LRU len | 缓冲池LRU列表中的总页面大小。 |
unzip_LRU len | 缓冲池unzip_LRU列表的长度(以页面为单位)。 |
I/O sum | 访问的缓冲池LRU列表页面总数。 |
I/O cur | 当前时间段内访问的缓冲池LRU列表页面总数。 |
I/O unzip sum | 已解压缩的缓冲池unzip_LRU列表页面总数。 |
I/O unzip cur | 当前时间段内已解压缩的缓冲池unzip_LRU列表页面总数。 |
说明:
youngs/s
指标仅适用于旧页面。它基于页面访问次数。给定页面可能有多次访问,所有访问都将被计入。如果您在没有发生大型扫描的情况下看到非常低的youngs/s
值,请考虑减少延迟时间或增加用于旧子列表的缓冲池百分比。增加百分比会使旧子列表变大,因此子列表中的页面需要更长时间才能移到尾部,这会增加再次访问这些页面并使它们变新的可能性。请参见第 17.8.3.3 节,“使缓冲池抗扫描”。non-youngs/s
指标仅适用于旧页面。它基于页面访问次数。给定页面可能有多次访问,所有访问都将被计入。如果您在执行大型表扫描时没有看到更高的non-youngs/s
值(以及更高的youngs/s
值),请增加延迟值。请参见第 17.8.3.3 节,“使缓冲池抗扫描”。young-making
率考虑所有缓冲池页面访问,而不仅仅是旧子列表中页面的访问。young-making
率和not
率通常不会加起来等于总的缓冲池命中率。旧子列表中的页面命中会导致页面移动到新子列表,但新子列表中的页面命中会导致页面仅在它们距头部一定距离时才移动到列表的头部。not (young-making 率)
是页面访问导致页面未变新的平均命中率,这是由于innodb_old_blocks_time
定义的延迟未满足,或由于新子列表中的页面命中未导致页面移动到头部。此比率考虑所有缓冲池页面访问,而不仅仅是旧子列表中页面的访问。
缓冲池服务器状态变量和INNODB_BUFFER_POOL_STATS
表提供了许多与InnoDB
标准监控输出中找到的缓冲池指标相同的指标。有关更多信息,请参见示例 17.10,“查询 INNODB_BUFFER_POOL_STATS 表”。