官方文档:https://dev.mysql.com/doc/refman/5.7/en/innodb-buffer-pool.html
Buffer Pool
缓冲池是主内存中的一个区域,在InnoDB
访问表和索引数据时会在其中进行 高速缓存。缓冲池允许直接从内存中处理经常使用的数据,从而加快了处理速度。在专用服务器上,通常将多达80%的物理内存分配给缓冲池。
为了提高大容量读取操作的效率,缓冲池被分为多个页面,这些页面可能包含多个行。为了提高缓存管理的效率,缓冲池被实现为页面的链接列表。使用LRU算法的变体将很少使用的数据从缓存中老化掉 。
知道如何利用缓冲池将经常访问的数据保留在内存中是MySQL优化的重要方面。
使用最近最少使用(LRU)算法的变体,将缓冲池作为列表进行管理。当需要空间以将新页面添加到缓冲池时,将驱逐最近使用最少的页面,并将新页面添加到列表的中间。此中点插入策略将列表视为两个子列表:
-
最前面是最近访问过的新页面(“年轻”) 的子列表
-
在末尾,是最近访问的旧页面的子列表
该算法将常用页面保留在新的子列表中。旧的子列表包含不常用的页面;这些页面是驱逐的候选对象。
默认情况下,该算法的运行方式如下:
-
3/8的缓冲池专用于旧的子列表。
-
列表的中点是新子列表的尾部与旧子列表的头相交的边界。
-
当
InnoDB
将页面读入缓冲池时,它首先将其插入中点(旧子列表的头部)。可以读取页面,因为它是用户启动的操作(例如SQL查询)所必需的,或者是的自动执行的预读操作的一部分InnoDB
。 -
访问旧子列表中的页面 使其变为“年轻”,将其移至新子列表的开头。如果由于用户启动的操作而需要读取页面,则将立即进行首次访问,并使页面年轻。如果由于预读操作而读取了该页面,则第一次访问不会立即发生,并且在退出该页面之前可能根本不会发生。
-
随着数据库的运行,通过移至列表的尾部,缓冲池中未被访问的页面将“老化”。新的和旧的子列表中的页面都会随着其他页面的更新而老化。随着将页面插入中点,旧子列表中的页面也会老化。最终,未使用的页面到达旧子列表的尾部并被逐出。
默认情况下,查询读取的页面会立即移入新的子列表,这意味着它们在缓冲池中的停留时间更长。例如,针对mysqldump操作或SELECT
不带WHERE
子句的 语句 执行的表扫描可以将大量数据带入缓冲池,并驱逐同等数量的旧数据,即使不再使用新数据也是如此。同样,由预读后台线程加载且仅访问一次的页面将移至新列表的开头。这些情况可能会将常用页面推送到旧的子列表,在此它们将被逐出。有关优化此行为的信息,请参见 第14.8.3.3节“使缓冲池扫描具有抵抗力”和 第14.8.3.4节“配置InnoDB缓冲池预取(预读)”。
InnoDB
标准监视器输出在BUFFER POOL AND MEMORY
有关缓冲池LRU算法操作的部分中包含几个字段。有关详细信息,请参阅使用InnoDB Standard Monitor监视缓冲池。
您可以配置缓冲池的各个方面以提高性能。
-
理想情况下,您可以将缓冲池的大小设置为与实际一样大的值,从而为服务器上的其他进程留出足够的内存以运行而不会进行过多的分页。缓冲池越大,就越
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节“保存和恢复缓冲池状态”。