Buffer Pool
缓冲池是InnoDB在主存中缓存表和索引数据的区域。缓冲池允许直接从内存访问频繁使用的数据,这加快了处理速度。在专用服务器上,高达80%的物理内存通常分配给缓冲池。
为了提高大容量读操作的效率,缓冲池被划分为可能容纳多行的page。为了提高缓存管理的效率,缓冲池被实现为页面的链表;使用最近最少使用(LRU)算法的变体将很少使用的数据从缓存中老化移除。
了解如何利用缓冲池将频繁访问的数据保存在内存中是MySQL调优的一个重要方面。
缓冲池LRU算法
使用变体LRU算法将缓冲池作为列表进行管理。当需要空间向缓冲池添加新页时,将删除最近最少使用的页,并将新页添加到列表的中间。这种中点插入策略将列表视为两个子列表:
- 在头部,最近被访问的新(”年轻”)页面的子列表
- 在尾部,一个最近访问次数较少的旧页面的子列表
Figure 15.2 Buffer Pool List

该算法将经常使用的页面保留在新的子列表(new sublist)中。旧的子列表(old sublist)包含较少使用的page;这些页面是eviction的候选页面。
默认情况下,算法运行如下:
- 3/8的缓冲池专门用于旧的子列表。
- 列表的中点是新子列表的尾部与旧子列表头部的交界处。
当
InnoDB将一个页面读入缓冲池时,它最初将它插入到中点(旧子列表的头部)。一个页面会在下面两种情况被读取,一是由用户发起的操作(如SQL查询)所需要的,二是由InnoDB自动执行的预读操作的一部分。 - 访问旧子列表中的page使其“年轻”,移动到新子列表的头部。如果读取该page是因为用户发起的操作需要该page,则立即进行第一次访问,并使该页处于年轻状态。如果由于预读操作读取了该page,那么第一次访问不会立即发生,并且可能在该page被逐出之前根本不会发生。
- 当数据库运行时,缓冲池中未被访问的页面通过向列表的尾部移动而“老化”。新子列表和旧子列表中的页面都会随着其他页面的更新而老化。旧子列表中的页面也会随着页面在中点插入而老化。最终,一个未使用的页面到达旧子列表的尾部并被驱逐。
默认情况下,查询读取的page会立即移动到新的子列表中,这意味着它们会在缓冲池中停留更长的时间。例如,对mysqldump操作,或不带WHERE查询条件的SELECT查询语句的执行,引起全表扫描会将大量数据带入缓冲池,并逐出等量的旧数据,即使新数据永远不会再次使用。类似地,由预读后台线程加载且仅访问一次的page将移动到新列表的头部。这些情况会将经常使用的页面推到旧的子列表中,在那里它们会被驱逐。有关优化此行为的信息,请参见第15.8.3.3节,“使缓冲池扫描抵抗”和第15.8.3.4节,“配置InnoDB缓冲池预取(预读)”。
InnoDB Standard Monitor的输出在BUFFER POOL AND MEMORY部分包含了几个关于缓冲池LRU算法操作的字段。详细信息请参见使用InnoDB Standard Monitor监控缓冲池。
缓冲池配置
您可以配置缓冲池的各个方面来提高性能。
- 理想的情况是,在给系统预留足够的空间的情况(避免使用swap)下,尽可能把innodb buffer pool设置的足够大。这样能够尽量做到一次读取,多次访问。buffer pool还可以缓存新插入和被修改的数据,这样可以把这些插入和修改进行合并提交,大大减少磁盘io的次数提高性能。参见第15.8.3.1节“配置InnoDB缓冲池大小”。
- 在64位操作系统上,有更大的内存能够利用,就可以将缓冲池分成多个部分(小的缓冲池),可以减少并发操作时相关资源的竞争。详细信息请参见第15.8.3.2节“配置多个缓冲池实例”。
- 您可以将经常访问的数据保存在内存中,而不用考虑全表扫描等操作带来的的突然峰值,这些操作会将大量不经常访问的数据带到缓冲池中。有关详细信息,请参见第15.8.3.3节,“使缓冲池扫描抵抗”。
- 您可以控制如何以及何时执行预读请求,在预期即将需要这些页面的时候,异步地将page预读到缓冲池中。详细信息请参见第15.8.3.4节“配置InnoDB缓冲池预取(预读)”。
- 您可以控制后台刷新的时间以及是否根据工作负载动态调整刷新速率。详细信息请参见第15.8.3.5节,“配置缓冲池刷新”。
- 你可以配置InnoDB如何保持当前缓冲池状态,以避免服务器重启后漫长的预热期。详细信息请参见第15.8.3.6节,“保存和恢复缓冲池状态”。
使用InnoDB Standard Monitor监控缓冲池
' InnoDB '标准监视器输出,可以使用' SHOW ENGINE InnoDB STATUS '访问,提供了关于缓冲池操作的度量。缓冲池指标位于' 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]
下表描述了' InnoDB '标准监视器报告的缓冲池指标。
' InnoDB ' Standard Monitor输出中提供的每秒平均值是基于' InnoDB ' Standard Monitor输出最后一次打印以来的运行时间。
Table 15.2 InnoDB Buffer Pool Metrics
| Name | Description |
|---|---|
| The total memory allocated for the buffer pool in bytes. | 分配给InnoDB数据字典的总内存(以字节为单位)。 |
| Dictionary memory allocated | 分配给缓冲池的总页面大小。 |
| Buffer pool size | 缓冲池空闲列表的总页面大小。 |
| Free buffers | 缓冲池LRU列表的总页面大小。 |
| Database pages | 缓冲池旧LRU子列表的总页面大小。 |
| Old database pages | 缓冲池中修改的当前页数。 |
| Modified db pages | 等待读入缓冲池的缓冲池页数。 |
| Pending reads | 缓冲池中要从LRU列表底部写入的旧脏页的数量。 |
| Pending writes LRU | 在检查点期间要刷新的缓冲池页数。 |
| Pending writes flush list | 缓冲池中挂起的独立页写次数。 |
| Pending writes single page | 缓冲池LRU列表中年轻的页的总数(移动到“新”页子列表的头部)。 |
| Pages made young | 缓冲池LRU列表中未设置为年轻的页面的总数(保留在“旧”子列表中但未设置为年轻的页面)。 |
| Pages made not young | 缓冲池LRU列表中导致页面年轻化的旧页面的每秒平均访问次数。有关更多信息,请参见该表后面的说明。 |
| youngs/s | 缓冲池LRU列表中导致页面不年轻的旧页面的每秒平均访问次数。有关更多信息,请参见该表后面的说明。 |
| non-youngs/s | 从缓冲池读取的总页数。 |
| Pages read | 在缓冲池中创建的页面总数。 |
| Pages created | 从缓冲池写入的总页数。 |
| Pages written | 每秒平均缓冲池页每秒读取数。 |
| reads/s | 每秒创建的缓冲池页面的平均数量。 |
| creates/s | 平均每秒写缓冲池页的次数。 |
| writes/s | 从缓冲池读取的页面与从磁盘存储读取的页面的缓冲池页面命中率。 |
| Buffer pool hit rate | 页面访问的平均点击率导致页面年轻。有关更多信息,请参见该表后面的说明。 |
| young-making rate | 页面访问的平均点击率没有导致页面年轻。有关更多信息,请参见该表后面的说明。 |
| not (young-making rate) | 每秒预读操作的平均值。 |
| Pages read ahead | 未从缓冲池中访问而被逐出的页面的每秒平均值。 |
| Pages evicted without access | 随机预读操作的每秒平均值。 |
| Random read ahead | 缓冲池LRU列表的总页面大小。 |
| LRU len | 缓冲池unzip_LRU列表的长度(以页为单位)。 |
| unzip_LRU len | 访问的缓冲池LRU列表页的总数。 |
| I/O sum | 当前间隔内访问的缓冲池LRU列表页的总数。 |
| I/O cur | 解压缩的缓冲池unzip_LRU列表页的总数。 |
| I/O unzip sum | 当前时间间隔内解压缩的缓冲池unzip_LRU列表页的总数。 |
注意:
youngs/s指标只适用于旧page。它基于page访问次数。对于给定的page可以有多次访问,所有访问都要计算在内。如果在没有大规模扫描的情况下看到非常低的young/s值,可以考虑减少延迟时间或增加用于旧子列表的缓冲池的百分比。增加百分比将使旧子列表变大,以便该子列表中的page移动到尾部需要更长的时间,可以增加了再次访问这些page并使其年轻的可能性。参见第15.8.3.3节,“使缓冲池扫描抵抗”。非young /s指标只适用于老page。它基于page访问次数。对于给定的page可以有多次访问,所有访问都要计算在内。如果在执行大型表扫描时没有看到更高的non-youngs/s值(以及更高的youngs/s值),则增加delay值。参见第15.8.3.3节,“使缓冲池扫描抵抗”.-young-making速率考虑所有缓冲池page访问,而不仅仅是旧子列表中的page访问。young-making率和not-young-making率通常不等于缓冲池的总命中率。旧子列表中的page点击会导致page移动到新的子列表中,但是新子列表中的page命中只会在它们与头部有一定的距离时,才会导致page移动到列表的头部。not (young-making rate)是指由于没有满足innodb_old_blocks_time定义的延迟,或者由于新子列表中的page命中没有导致页面移动到头部,page访问没有导致page变年轻的平均点击率。此速率考虑所有缓冲池页面访问,而不仅仅是对旧子列表中的页面的访问。
缓冲池服务器状态变量和' INNODB_BUFFER_POOL_STATS '表提供了许多与InnoDBStandard Monitor输出中相同的缓冲池指标。更多信息请参见示例15.10,“查询INNODB_BUFFER_POOL_STATS表”。