mysql数据库中的缓存命中率与查询优化

10次阅读

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

mysql数据库中的缓存命中率与查询优化

MySQL 查询缓存(query_cache)已彻底移除,别再查命中率了

MySQL 8.0 起,query_cache_typequery_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 BYLIMIT 组合时,确保排序字段在索引中覆盖,否则触发 using filesort

一个典型陷阱:select * FROM orders WHERE status IN ('paid','shipped') ORDER BY created_at DESC LIMIT 20 —— 若没建 (status, created_at) 联合索引,即使 status 有单列索引,仍大概率走全表扫描+临时文件排序。

其他影响“感知性能”的缓存层不能忽略

应用端和中间件的缓存行为,往往比数据库内置机制更关键:

  • 连接池(如 HikariCP)的 maxLifetimeidleTimeout 设置不当,会导致频繁重连,掩盖真实 SQL 性能问题
  • redis 缓存穿透/雪崩会使大量请求直打 MySQL,此时看到的“慢查询”其实是缓存缺失引发的并发冲击
  • ORM 框架(如 mybatis 的二级缓存、hibernate@Cache)若未合理配置 timeToLiveSeconds,可能返回陈旧数据,或因缓存击穿引发 DB 突增

查一条 SQL 很快,但线上接口 P99 延迟飙升?先确认是不是缓存层失效导致流量洪峰直接压到了 MySQL 连接数和缓冲池上。

text=ZqhQzanResources