InnoDB
并没有使用严格的 LRU 算法,而是使用了一种技术来最小化加载到 缓冲池 中并且不再访问的数据量。目标是确保频繁访问的(“热”)页面保留在缓冲池中,即使 预读 和 全表扫描 加载了可能或不可能在之后访问的新块。
新读取的块被插入到 LRU 列表的中间。所有新读取的页面都被插入到默认情况下距离 LRU 列表尾部 3/8
的位置。当页面在缓冲池中第一次被访问时,它们会被移动到列表的开头(最近使用端)。因此,从未被访问过的页面永远不会到达 LRU 列表的前部,并且比使用严格的 LRU 方法更快地“老化”。这种安排将 LRU 列表划分为两个部分,其中插入点下游的页面被认为是“旧的”,并且是 LRU 驱逐的理想受害者。
有关 InnoDB
缓冲池内部工作原理以及有关 LRU 算法的详细信息,请参见 第 17.5.1 节“缓冲池”。
您可以控制 LRU 列表中的插入点,并选择 InnoDB
是否将相同的优化应用于通过表或索引扫描加载到缓冲池中的块。配置参数 innodb_old_blocks_pct
控制 LRU 列表中“旧”块的百分比。 innodb_old_blocks_pct
的默认值为 37
,对应于原始的固定比例 3/8。值范围为 5
(缓冲池中的新页面非常快地老化)到 95
(只有 5% 的缓冲池保留给热页面,使算法接近熟悉的 LRU 策略)。
防止缓冲池被预读冲刷的优化可以避免由于表或索引扫描而导致的类似问题。在这些扫描中,数据页面通常会在快速连续的几次访问中被访问,然后就再也不会被访问了。配置参数 innodb_old_blocks_time
指定在扫描期间第一次访问页面后,该页面可以被访问而不会被移动到 LRU 列表的开头(最近使用端)的时间窗口(以毫秒为单位)。 innodb_old_blocks_time
的默认值为 1000
。增加此值会使越来越多的块更有可能从缓冲池中更快地老化。
innodb_old_blocks_pct
和 innodb_old_blocks_time
都可以在 MySQL 选项文件(my.cnf
或 my.ini
)中指定,也可以使用 SET GLOBAL
语句在运行时更改。在运行时更改值需要足够的权限来设置全局系统变量。请参见 第 7.1.9.1 节“系统变量权限”。
为了帮助您衡量设置这些参数的效果,SHOW ENGINE INNODB STATUS
语句报告缓冲池统计信息。有关详细信息,请参见 使用 InnoDB 标准监视器监控缓冲池。
由于这些参数的效果会根据您的硬件配置、数据和工作负载的细节而有很大差异,因此在任何性能关键型或生产环境中更改这些设置之前,请务必进行基准测试以验证其有效性。
在混合工作负载中,大多数活动都是 OLTP 类型,并定期执行导致大范围扫描的批处理报告查询,在批处理运行期间设置 innodb_old_blocks_time
的值可以帮助将正常工作负载的工作集保留在缓冲池中。
当扫描无法完全放入缓冲池的大型表时,将 innodb_old_blocks_pct
设置为较小的值可以防止只读一次的数据占用缓冲池的大部分空间。例如,将 innodb_old_blocks_pct=5
设置为仅读取一次的这些数据最多占缓冲池的 5%。
当扫描可以完全放入内存的小型表时,在缓冲池中移动页面周围的开销较小,因此您可以将 innodb_old_blocks_pct
保持为其默认值,甚至更高,例如 innodb_old_blocks_pct=50
。
innodb_old_blocks_time
参数的效果比 innodb_old_blocks_pct
参数更难以预测,相对较小,并且随工作负载的变化而变化更大。如果调整 innodb_old_blocks_pct
的性能改进不足,请进行自己的基准测试以获得最佳值。