mysql 5.7 查询缓存对 innodb 高并发写入场景有害无益,因其表级失效机制、锁瓶颈及低命中率导致性能倒退;应关闭 query_cache_type 并专注优化 innodb_buffer_pool_size。

MySQL 5.7 的查询缓存(Query Cache)不仅不能稳定提升 QPS,反而极易与 InnoDB 的高并发写入产生冲突,导致缓存频繁失效、锁表、甚至拖慢整体响应。它不是“开就变快”,而是“开了更难调”。
为什么 query_cache_type=ON 在 InnoDB 场景下常引发性能倒退
查询缓存的失效粒度是「表级」:只要对某张表执行 INSERT、UPDATE、DELETE,这张表对应的所有缓存条目立刻被清空。InnoDB 表若存在中等以上写压力(比如每秒几十次 DML),缓存命中率会断崖式下跌,Qcache_lowmem_prunes 和 Qcache_inserts 比值持续走高,说明缓存刚存进去就被踢掉。
更关键的是,FLUSH QUERY CACHE 或缓存整理过程会锁住整个查询缓存模块,阻塞后续查询——这不是并发问题,是串行瓶颈。
- 典型症状:
SHOW STATUS LIKE 'Qcache%'中Qcache_hits极低,Qcache_lowmem_prunes每分钟增长数百甚至上千 - InnoDB 表越活跃,查询缓存收益越接近零,甚至为负
- 即使只读从库,若主库同步频繁,从库的查询缓存也会被
SQL_THREAD触发的隐式刷新清空
如何判断当前查询缓存是否在拖后腿
别猜,直接查状态变量和实际行为:
- 运行
SHOW VARIABLES LIKE 'query_cache_type':值为ON(1)才启用;DEMAND(2)需显式加SQL_CACHE;OFF(0)即关闭 - 立即执行
SHOW STATUS LIKE 'Qcache%',重点关注三个数:Qcache_hits(命中)、Qcache_inserts(插入)、Qcache_lowmem_prunes(淘汰) - 计算粗略命中率:
(Qcache_hits / (Qcache_hits + Qcache_inserts)) * 100%;低于 30% 基本可判定无效 - 对比开启/关闭时的
Com_select和Slow_queries:如果关掉query_cache_type后慢查询没涨、平均响应时间反而降了,说明缓存早就在制造假象
关闭查询缓存比调优更安全、更有效
对纯 InnoDB 环境,关闭是首选操作,而非反复调整 query_cache_size 或 query_cache_min_res_unit。这些参数治标不治本,且容易掩盖真实瓶颈。
- 临时关闭(重启失效):
SET GLOBAL query_cache_type = OFF; - 永久关闭:编辑
my.cnf,在[mysqld]下添加或修改两行:query_cache_type = 0query_cache_size = 0 - 确认生效:
SELECT @@query_cache_type, @@query_cache_size;应返回0和0 - 注意:关闭后所有带
SQL_CACHE的语句自动退化为普通查询,无需改应用代码
真正该投入精力优化的缓存层:InnoDB Buffer Pool
把原来想花在 query cache 上的调优时间,全挪到 innodb_buffer_pool_size 上——这才是 InnoDB 实际用到的、影响 90% 读性能的核心缓存。
- 先看当前值:
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';,若远小于物理内存的 50%,大概率是瓶颈 - 检查命中率:
SELECT (1 - VARIABLE_VALUE / (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_buffer_pool_read_requests')) * 100 AS hit_rate FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_buffer_pool_reads'; - 命中率低于 95%?优先增大
innodb_buffer_pool_size,而不是回头动 query cache - 搭配
innodb_buffer_pool_instances = 8(当 buffer pool > 1G 时),减少内部争用
查询缓存是个历史包袱,InnoDB 的事务机制和 MVCC 天然不适合它。你看到的“缓存命中”,很多时候只是延迟暴露了慢查询——真正该盯紧的,是 buffer pool 命中率和慢查询日志里反复出现的那几条 SQL。











