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 连接数和缓冲池上。
