与使用严格的 LRU 算法不同,InnoDB
使用一种技术来最小化被引入 缓冲池 且从未访问过的数据的数量。目标是确保经常访问的(“热”)页面保留在缓冲池中,即使 预读 和 全表扫描 引入可能或不可能之后访问的新块。
新读取的块被插入到 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
后,如果性能提升不足,则进行自己的基准测试。