MySQL 查询缓存(Query Cache)已弃用,别再依赖它做性能优化
MySQL 8.0 已彻底移除
query_cache_type和相关参数,5.7 是最后一个支持它的稳定版本。如果你还在查
Qcache_hits、
Qcache_inserts这类状态变量,说明你可能正踩在一个过时的优化思路上——缓存命中率 ≠ 实际性能收益,尤其在写多读少或表频繁变更的场景下,查询缓存反而会成为锁争用瓶颈。
真正影响 SQL 执行性能的缓存层是 InnoDB Buffer Pool
现代 MySQL 性能分析应聚焦
innodb_buffer_pool_reads(物理磁盘读)与
innodb_buffer_pool_read_requests(逻辑读请求)的比值,这才是衡量「热数据缓存效果」的关键指标:
SELECT
ROUND((1 - (ibp_reads / ibp_read_requests)) * 100, 2) AS buffer_pool_hit_rate
FROM (
SELECT
VARIABLE_VALUE AS ibp_reads
FROM performance_schema.global_status
WHERE VARIABLE_NAME = 'Innodb_buffer_pool_reads'
) r
CROSS JOIN (
SELECT
VARIABLE_VALUE AS ibp_read_requests
FROM performance_schema.global_status
WHERE VARIABLE_NAME = 'Innodb_buffer_pool_read_requests'
) req;
Innodb_buffer_pool_reads > 0表示有磁盘 I/O,需关注是否 buffer pool 太小或查询未走索引 命中率长期低于 95% 通常意味着 buffer pool 不足,或存在大量全表扫描 该指标只反映页级缓存效果,不等同于“SQL 结果被缓存”,和旧版 Query Cache 完全无关
如何判断某条 SQL 是否真的从 Buffer Pool 中受益
单条语句无法直接看到“本次执行是否命中 Buffer Pool”,但可通过
EXPLAIN FORMAT=JSON+ 执行前后状态差定位真实开销: 先执行
SHOW STATUS LIKE 'Innodb_buffer_pool_read%';记下
Innodb_buffer_pool_read_requests和
Innodb_buffer_pool_reads运行目标 SQL(确保无其他并发干扰) 再次执行
SHOW STATUS,观察
Innodb_buffer_pool_reads是否增加:若增加,说明有页未命中,触发了磁盘读 配合
EXPLAIN FORMAT=JSON查看
rows_examined和
used_columns,确认是否走了预期索引
注意:
Handler_read_*系列状态(如
Handler_read_next)反映的是存储引擎扫描行为,不是缓存命中指标,勿混淆。
performance_schema 中可跟踪的缓存相关事件
想深入分析某类操作的内存/IO 模式,开启以下 instruments 后查
events_waits_history_long:
UPDATE performance_schema.setup_instruments SET ENABLED = 'YES', TIMED = 'YES' WHERE NAME LIKE 'wait/io/file/innodb/%' OR NAME LIKE 'wait/synch/mutex/innodb/%';重点关注
wait/io/file/innodb/innodb_data_file—— 表示实际磁盘读写等待
wait/synch/mutex/innodb/buf_pool_mutex高频出现?说明 buffer pool latch 争用严重,可能是 buffer pool 过大且未启用
innodb_buffer_pool_instances这些事件不会告诉你“缓存命中”,但能暴露缓存失效或争用的真实代价
Buffer Pool 的大小、实例数、预热策略、以及 SQL 是否能复用已有页帧,远比“缓存命中率”这个数字更能决定性能。盯着一个被废弃的指标,不如先确认你的
innodb_buffer_pool_size是否设为物理内存的 50%–75%,以及有没有定期用
SELECT * FROM table LIMIT 1类操作意外刷掉热页。
