而不是使用严格的 LRU 算法,InnoDB
使用一种技术来最小化将数据带入缓冲池并且从不再访问的数据量。目标是确保频繁访问的(“热”)页面保持在缓冲池中,即使 预读 和 全表扫描 将新的块带入缓冲池中。
新读取的块被插入到 LRU 列表的中间。所有新读取的页面都被插入到 LRU 列表的默认位置,即从尾部的 3/8
处。这些页面在缓冲池中第一次被访问时被移到列表的最前端(最近使用的端)。因此,从不被访问的页面从不移到 LRU 列表的前端,并且比严格的 LRU 方法更快地““老化”。这种安排将 LRU 列表分为两个部分,其中下游的页面被认为是 “老” 并且是 LRU 驱逐的理想受害者。
关于 InnoDB
缓冲池的内部工作机制和 LRU 算法的详细信息,请参阅 第 17.5.1 节,“缓冲池”。
您可以控制 LRU 列表中的插入点,并选择是否将相同的优化应用于表或索引扫描带入缓冲池的块。配置参数 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
。增加该值将使得更多的块更快地从缓冲池中老化。
可以在 MySQL 选项文件(my.cnf
或 my.ini
)中指定 innodb_old_blocks_pct
和 innodb_old_blocks_time
,也可以使用 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
的性能改进不够。