缓冲池是InnoDB在主内存中缓存表和索引数据的地方,以便快速访问。缓冲池允许频繁使用的数据直接从内存中访问,从而加速处理。在专用服务器上,通常将物理内存的80%分配给缓冲池。
为了高效地执行大量读取操作,缓冲池被分割成可以容纳多行的页面。为了高效地管理缓存,缓冲池被实现为一个链表的页面;不常用的数据使用一种变体的最近最少使用(LRU)算法被逐出缓存。
了解如何利用缓冲池来保持频繁访问的数据在内存中是一个重要的MySQL调整方面。
缓冲池被管理为一个列表,使用一种变体的 LRU 算法。当需要添加新页面到缓冲池时,最少使用的页面被逐出,新的页面被添加到列表的中间。这中间插入策略将列表分为两个子列表:
-
在头部,一个子列表包含最近访问的(“年轻的”)页面
-
在尾部,一个子列表包含不太常用的页面;这些页面是逐出候选项
算法将频繁使用的页面保持在新子列表中。老子列表包含不太常用的页面;这些页面是逐出候选项。
默认情况下,算法按照以下方式操作:
-
缓冲池的 3/8 被分配给老子列表。
-
列表的中点是新子列表的尾部和老子列表的头部的交界点。
-
当 InnoDB 将页面读入缓冲池时,最初将其插入到中点(老子列表的头部)。页面可以被读取,因为它是用户启动的操作所需的,或者作为 InnoDB 自动执行的读取预读操作的一部分。
-
访问老子列表中的页面使其变“年轻”,将其移到新子列表的头部。如果页面是由于用户启动的操作所需的,那么第一次访问立即发生。如果页面是由于读取预读操作所需的,那么第一次访问可能不会立即发生,或者可能根本不会发生。
-
随着数据库的操作,缓冲池中的页面如果不被访问就会“老化”,移动到列表的尾部。页面在新子列表和老子列表中都会老化。页面在老子列表中也会老化,因为页面被插入到中点。最终,一个未使用的页面将到达老子列表的尾部并被逐出。
默认情况下,查询读取的页面立即被移到新子列表中,这意味着它们将在缓冲池中停留更长时间。例如,mysqldump 操作或 SELECT 语句没有 WHERE 子句的表扫描可以将大量数据带入缓冲池,并逐出等量的旧数据,即使新数据从不再被使用。类似地,read-ahead 背景线程加载的页面如果只被访问一次,也会被移到新子列表的头部。这些情况可能会将频繁使用的页面推到老子列表中,使其成为逐出候选项。有关优化这种行为的信息,请参见第 17.8.3.3 节,“使缓冲池扫描抵抗”和第 17.8.3.4 节,“配置 InnoDB 缓冲池预读(读取预读)”。
InnoDB
标准监控输出包含了缓冲池 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 缓冲池指标
Name | Description |
---|---|
总内存分配 | 缓冲池的总内存分配(以字节为单位)。 |
数据字典内存分配 | InnoDB 数据字典的总内存分配(以字节为单位)。 |
缓冲池大小 | 缓冲池的总大小(以页为单位)。 |
空闲缓冲区 | 缓冲池空闲列表的总大小(以页为单位)。 |
数据库页 | 缓冲池 LRU 列表的总大小(以页为单位)。 |
旧数据库页 | 缓冲池旧 LRU 子列表的总大小(以页为单位)。 |
修改的 db 页 | 缓冲池中当前修改的页数。 |
挂起的读取 | 缓冲池中等待读取的页数。 |
挂起的写入 LRU | 缓冲池中等待写入的旧页数。 |
挂起的写入刷新列表 | 缓冲池中等待刷新的页数。 |
挂起的单页写入 | 缓冲池中等待独立写入的页数。 |
页被设为年轻 | 缓冲池 LRU 列表中页被设为年轻的总数(移到“新”子列表的头部)。 |
页未被设为年轻 | 缓冲池 LRU 列表中页未被设为年轻的总数(页保持在“旧”子列表中)。 |
每秒年轻化 | 缓冲池 LRU 列表中每秒访问旧页的平均次数,导致页被设为年轻。查看下表的注释以获取更多信息。 |
每秒非年轻化 | 每秒访问旧页面的缓冲池LRU列表的平均值,未使页面变年轻。请参阅下表中的注释以获取更多信息。 |
读取页面 | 从缓冲池中读取的总页数。 |
创建页面 | 在缓冲池中创建的总页数。 |
写入页面 | 从缓冲池中写入的总页数。 |
读取/秒 | 每秒缓冲池页面读取的平均数。 |
创建/秒 | 每秒缓冲池页面创建的平均数。 |
写入/秒 | 每秒缓冲池页面写入的平均数。 |
缓冲池命中率 | 从缓冲池中读取页面的命中率vs从磁盘存储中读取。 |
年轻化率 | 页面访问结果使页面变年轻的平均命中率。请参阅下表中的注释以获取更多信息。 |
非年轻化率 | 页面访问结果未使页面变年轻的平均命中率。请参阅下表中的注释以获取更多信息。 |
预读页面 | 每秒预读操作的平均数。 |
未访问的页面被驱逐 | 每秒从缓冲池中未被访问的页面被驱逐的平均数。 |
随机预读 | 每秒随机预读操作的平均数。 |
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
指标仅适用于旧页面。它基于页面访问次数。可以对同一页进行多次访问,所有这些访问都将被计数。如果您没有看到更高的non-youngs/s
值,而您正在执行大型表扫描(并且看到更高的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 表”。