mysql迁移后buffer pool命中率掉至900以下主因是冷启动未启用预热,需同时配置innodb_buffer_pool_dump_at_shutdown=on和innodb_buffer_pool_load_at_startup=on,并确保ib_buffer_pool文件权限正确、合理设置dump_pct及old_blocks参数以适配业务热点模式。

迁移后Buffer Pool命中率掉到900以下,大概率没开预热
新环境MySQL重启后Buffer Pool是空的,所有查询都得走磁盘——这不是配置错了,是“冷启动”被当成了常态。很多团队查完innodb_buffer_pool_size觉得没问题就收工,结果第二天一早慢查询报警炸了。关键不是缓存池大小,而是它有没有“记住”上一次的热点。
必须同时打开dump和load两个开关,缺一不可
只设innodb_buffer_pool_dump_at_shutdown = ON,关机时会生成ib_buffer_pool文件;但如果不配innodb_buffer_pool_load_at_startup = ON,启动时根本不会读它。这两个参数像一对开关,单开一个等于没开。
-
ib_buffer_pool默认放在datadir下,确认MySQL进程对该路径有读写权限(Docker里常见挂载目录权限不对、SELinux拒绝写入) - 首次加载耗时取决于dump文件大小,可设
innodb_buffer_pool_dump_pct = 75,只保留最热75%的页,缩短加载时间 - MySQL 5.7+ 支持动态启用,但
LOAD动作只在启动时触发,运行中改参数不生效
预热脚本不是万能的,得看业务访问模式
如果业务是周期性报表(比如每天凌晨跑一次大汇总),用预热脚本能提前把相关表页加载进Buffer Pool;但如果是用户随机点查、热点分散,脚本预热反而可能挤出真实热点——这时候更该优化SQL或加索引,而不是硬塞数据。
- 简单预热脚本示例:
mysql -u root -e "SELECT * FROM hot_table LIMIT 1;" your_db
,本质是触发物理读,把页拉进缓存 - 别用
SELECT COUNT(*)这类全表扫描语句预热,它会把冷数据也拖进来,污染LRU链 - 真正有效的预热,应该基于
performance_schema.table_io_waits_summary_by_table找出过去24小时IO最高的几张表,针对性地SELECT * FROM t WHERE id IN (…)拉几行
别忽略innodb_old_blocks_pct对预热效果的影响
默认37%的LRU“老区”是为防全表扫描污染设计的,但预热加载的数据刚进来就被扔进老区,如果innodb_old_blocks_time太短(默认1000ms),这些页可能还没被访问几次就被踢出去了。
- 对稳定热点业务,可试调高
innodb_old_blocks_pct = 50,让预热数据更容易晋升到新生代 - 但别无脑调高——如果业务本身就有大量临时扫描,这反而会让真实热点更难驻留
- 观察指标:
Innodb_buffer_pool_reads是否持续下降、Innodb_buffer_pool_read_requests是否稳定上升,比单纯看“命中率数字”更准
预热不是一劳永逸的事,尤其当业务数据分布或访问节奏变化时,dump文件会过期;真正容易被忽略的是:你每次改了SQL或加了索引,都该重新评估哪些页算“热点”。











