buffer pool命中率准确计算公式为(innodb_buffer_pool_read_requests - innodb_buffer_pool_reads) / innodb_buffer_pool_read_requests,需用show global status获取实时值,避免performance schema子查询时间错位;命中率高不等于无i/o瓶颈,须结合innodb_buffer_pool_reads绝对值、变化趋势及sql执行计划综合判断。

Buffer Pool命中率不能只看百分比,得结合Innodb_buffer_pool_reads的绝对值和变化趋势一起判断。
怎么算出准确的 Buffer Pool 命中率
公式本身很简单:(Innodb_buffer_pool_read_requests - Innodb_buffer_pool_reads) / Innodb_buffer_pool_read_requests,但要注意两点:一是必须用 SHOW GLOBAL STATUS 查实时值,而不是 INFORMATION_SCHEMA.INNODB_METRICS(它默认不开启且统计口径不同);二是别用 Performance Schema 里拼接子查询的方式——容易因并发导致两个变量取值时间点错位,结果失真。
推荐直接执行:
SELECT
ROUND((1 - reads / requests) * 100, 2) AS hit_rate,
reads, requests
FROM (
SELECT
VARIABLE_VALUE AS reads
FROM performance_schema.global_status
WHERE VARIABLE_NAME = 'Innodb_buffer_pool_reads'
) r
CROSS JOIN (
SELECT
VARIABLE_VALUE AS requests
FROM performance_schema.global_status
WHERE VARIABLE_NAME = 'Innodb_buffer_pool_read_requests'
) req;
-
Innodb_buffer_pool_reads是从磁盘读页的次数,这个数越小越好 -
Innodb_buffer_pool_read_requests是所有读请求总数,包括命中和未命中的 - 如果命中率显示 99.2%,但
Innodb_buffer_pool_reads每秒稳定在 80+,说明仍有大量热数据没进缓存,或存在频繁回表/排序
命中率高 ≠ 没 I/O 瓶颈
常见误判场景:命中率 99.5%,但应用响应变慢、w_await 超过 15ms(NVMe)、iotop 显示 mysqld 进程持续刷出小 IO。这时候问题往往不在缓存大小,而在 SQL 本身——比如 ORDER BY 触发 Using filesort,或 JOIN 缺少索引导致全表扫描。
- 查
SHOW ENGINE INNODB STATUS\G,重点关注 BUFFER POOL AND MEMORY 段里的Pages read和Pages created,前者远高于后者,说明读放大严重 - MySQL 8.0.22+ 可用
EXPLAIN FORMAT=JSON查disk_reads字段,提前预估单条语句的磁盘读压力 - 用
sys.statement_analysis或performance_schema.events_statements_summary_by_digest找出SUM_ROWS_EXAMINED高但SUM_ROWS_SENT低的语句——大概率是扫了大量数据只返回几行
哪些值要盯住,而不是只看命中率
单独一个命中率数字没有上下文就等于没监控。真正需要持续观察的是这几个状态变量的组合:
-
Innodb_buffer_pool_pages_free:空闲页持续低于总页数的 5%,说明缓存长期紧张,不是配置小就是有内存泄漏(如大事务长期持有页) -
Innodb_buffer_pool_pages_dirty:脏页数持续 > 1000,意味着刷盘跟不上写入节奏,可能拖慢后续写操作甚至触发强制刷盘阻塞 -
Innodb_buffer_pool_wait_free:非零值表示有线程在等空闲页,说明 LRU 淘汰或刷新跟不上分配速度,这是更底层的瓶颈信号 -
Innodb_buffer_pool_read_ahead_rnd和Innodb_buffer_pool_read_ahead_seq:这两个值突然升高,基本可以定位到某类范围查询或全表扫描正在发生
命中率只是入口,真正的复杂点在于把 Innodb_buffer_pool_reads 的数值变化和具体 SQL 行为、系统 I/O 响应(w_await、aqu-sz)对齐。否则你优化了半天 buffer pool size,结果发现慢查询根本没走索引,全是白忙。











