mysql 5.7 中 query cache 不是失效才拖慢,而是启用即成隐性全局锁瓶颈;每次查询需争抢 query_cache_lock,写操作触发全表缓存清空,命中率常低于5%,且配置残留(如 query_cache_size>0)会自动激活,必须彻底删除所有 querycache* 配置并重启生效。

MySQL 5.7 中的 Query Cache 不是“失效了才变慢”,而是**只要启用,就大概率在拖慢响应**——它根本不是缓存加速器,而是一个隐性全局锁瓶颈。
query_cache_type = 1 实际上是全局 mutex 锁开关
每次 SELECT 执行前,都要抢 query_cache_lock 这把全局互斥锁。哪怕你只读一张表,只要其他线程在写任何表(比如日志表、计数器表),这个锁就会排队阻塞。高并发下,perf top -p $(pgrep mysqld) 会高频出现 query_cache_lock 符号,线程卡在等待状态。
- 写操作(INSERT/UPDATE/DELETE)触发的是「全表缓存清空」,不是局部失效:哪怕只改一行,该表所有缓存条目全丢
-
Qcache_lowmem_prunes持续上涨,说明缓存刚写入就被踢出,Qcache_hits却几乎不涨 → 白忙活还占资源 - 即使
SELECT SQL_NO_CACHE,也要走一遍缓存判断逻辑,多一次哈希计算和锁检查
命中率低 ≠ 不耗资源,而是“负收益”
你以为缓存没命中就不花钱?错。Query Cache 的开销是刚性的:SQL 文本哈希、结果集序列化、内存块管理、碎片整理……这些都在每次查询时发生,无论最终是否缓存成功。
- 命中率低于 5% 很常见,但
Qcache_inserts接近Com_select→ 几乎每条 SELECT 都尝试缓存 -
query_cache_min_res_unit默认 4KB,一个 12KB 结果要分 3 块写入,每次写都抢锁 - SQL 文本里多一个空格、换行、注释,就被视为全新语句 → 缓存利用率天然低下
配置残留会让它“偷偷复活”
你没写 query_cache_type,但只要配置文件里留着 query_cache_size = 1048576,MySQL 5.7 就会自动把 query_cache_type 拉回 1 —— 它的默认逻辑是 “size > 0 → type = 1”。
-
SET GLOBAL query_cache_type = OFF只是临时停用,重启后立即恢复 - 必须删光所有
query_cache_*行(包括query_cache_limit、query_cache_min_res_unit),再systemctl restart mysqld - 确认生效:执行
SHOW VARIABLES LIKE 'query_cache%',全部返回OFF或0,且SHOW STATUS LIKE 'Qcache%'中Qcache_hits不再增长
最易被忽略的点:关掉 Query Cache 后,性能提升往往不是因为“缓存没了”,而是释放了那把一直卡着所有查询的 query_cache_lock。真正该调的,从来都是 innodb_buffer_pool_size 和索引设计,不是 query_cache_size。











