MySQL 8.0 起查询缓存已彻底移除,相关变量和监控指标(如 Qcache_hits)均无效;应转而关注 InnoDB 缓冲池命中率(1 - Innodb_buffer_pool_reads / Innodb_buffer_pool_read_requests),并优化 SQL 执行计划与索引。

MySQL 查询缓存(query_cache)已彻底移除,别再查命中率了
MySQL 8.0 起,query_cache_type、query_cache_size 等所有查询缓存相关变量已被删除。执行 SHOW VARIABLES LIKE 'query_cache%' 将返回空结果;设置它们会报错 Unknown system variable。这意味着你无法再通过 Qcache_hits / (Qcache_hits + Qcache_inserts) 这类公式计算“查询缓存命中率”——因为那个缓存根本不存在了。
如果你还在监控 Qcache_hits 或依赖 mysqladmin extended -r -i 1 | grep Qcache,说明你可能:
- 运行的是 MySQL 5.7 或更早版本(需尽快升级)
- 误把 InnoDB 缓冲池(
innodb_buffer_pool)指标当成查询缓存指标 - 被过时的运维文档或监控脚本误导
真正该看的缓存:InnoDB 缓冲池命中率
InnoDB 缓冲池(innodb_buffer_pool)才是 MySQL 实际用到的核心缓存。它的“命中率”反映的是热数据是否常驻内存,直接影响磁盘 I/O 压力。计算公式为:
1 - (Innodb_buffer_pool_reads / Innodb_buffer_pool_read_requests)
其中:
-
Innodb_buffer_pool_reads:缓冲池未命中、必须从磁盘读取页的次数(越低越好) -
Innodb_buffer_pool_read_requests:总逻辑读请求数(包括命中和未命中)
健康阈值通常应 > 99%。低于 95% 就值得排查:innodb_buffer_pool_size 是否太小?是否有大范围全表扫描?
实时查看命令示例:
mysql -e "SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_%reads';"
没有查询缓存后,优化重点转向执行计划与索引
过去靠查询缓存“掩盖”慢查询,现在每条语句都真实执行。优化必须落到 SQL 层面:
- 用
EXPLAIN检查type字段:避免ALL(全表扫描),优先const/ref/range - 确认
key列是否用了预期索引;key_len是否符合联合索引最左匹配 - 警惕隐式类型转换:比如
WHERE user_id = '123'(字段是INT)会导致索引失效 -
ORDER BY和LIMIT组合时,确保排序字段在索引中覆盖,否则触发Using filesort
一个典型陷阱:SELECT * FROM orders WHERE status IN ('paid','shipped') ORDER BY created_at DESC LIMIT 20 —— 若没建 (status, created_at) 联合索引,即使 status 有单列索引,仍大概率走全表扫描+临时文件排序。
其他影响“感知性能”的缓存层不能忽略
应用端和中间件的缓存行为,往往比数据库内置机制更关键:
- 连接池(如 HikariCP)的
maxLifetime和idleTimeout设置不当,会导致频繁重连,掩盖真实 SQL 性能问题 - Redis 缓存穿透/雪崩会使大量请求直打 MySQL,此时看到的“慢查询”其实是缓存缺失引发的并发冲击
- ORM 框架(如 MyBatis 的二级缓存、Hibernate 的
@Cache)若未合理配置timeToLiveSeconds,可能返回陈旧数据,或因缓存击穿引发 DB 突增
查一条 SQL 很快,但线上接口 P99 延迟飙升?先确认是不是缓存层失效导致流量洪峰直接压到了 MySQL 连接数和缓冲池上。










