准确命中率必须通过innodb_buffer_pool_read_requests与innodb_buffer_pool_reads计算:(requests−reads)/requests×100%,需用show global status获取实时值,弃用show engine innodb status中的滑动窗口指标。

别信 SHOW ENGINE INNODB STATUS 里那个 Buffer pool hit rate,它只是最近 1000 次读的滑动窗口统计,生产环境必须弃用。
怎么算才是准确命中率?
真正该盯的两个指标是 Innodb_buffer_pool_read_requests(所有逻辑读请求)和 Innodb_buffer_pool_reads(真正从磁盘读页的次数)。命中率公式是:(requests - reads) / requests * 100%。
- 必须用
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read%'直接查,避免通过INFORMATION_SCHEMA.INNODB_METRICS或 Performance Schema 子查询——后者两个值取样时间点可能错位 - MySQL 默认整数除法会截断,写 SQL 时得显式转浮点,比如用
ROUND((1 - b.Variable_value/a.Variable_value) * 100, 2) - 推荐一行查完:
SELECT ROUND((1 - b.Variable_value/a.Variable_value) * 100, 2) AS hit_rate FROM performance_schema.global_status a JOIN performance_schema.global_status b ON a.Variable_name = 'Innodb_buffer_pool_read_requests' AND b.Variable_name = 'Innodb_buffer_pool_reads';
刚调大 innodb_buffer_pool_size 后数据不准怎么办?
InnoDB 是异步 resize 的,Innodb_buffer_pool_pages_total 和 Innodb_buffer_pool_pages_free 会持续波动至少 5 分钟。此时 Innodb_buffer_pool_read_requests 分母不稳定,算出的命中率会偏低失真。
- 等
Innodb_buffer_pool_pages_free不再剧烈下降、且连续两分钟变化 ≤ 10 页再采样 - 冷启动阶段(MySQL 刚启)前 30 分钟命中率天然偏低,不具参考价值
- 如果发现
Innodb_buffer_pool_reads每秒稳定在 50+,哪怕命中率显示 99.2%,也说明仍有大量热数据没进缓存,或 SQL 在反复回表、排序、扫描
命中率高 ≠ 没 I/O 压力
99% 看着漂亮,但得看背后行为:
-
Innodb_buffer_pool_reads每秒值持续 > 20,说明物理读压力真实存在 - 查
SHOW ENGINE INNODB STATUS\G中 BUFFER POOL AND MEMORY 段的Pages read和Pages created:前者远高于后者,说明读放大严重 - 命中率只是入口指标,真正卡顿往往藏在单条 SQL 的物理读行为里——与其盯着百分比,不如定期抓
Innodb_buffer_pool_reads的每秒增量,结合慢日志定位问题 SQL
最易被忽略的是:命中率本身不告诉你哪条 SQL 在刷盘,也不反映 LRU 链表是否被全表扫描污染。调参前,先看 innodb_old_blocks_pct 和实际访问模式是否匹配。











