Query Cache在高并发下因全局锁Qcache_lock导致严重性能瓶颈,应永久禁用并调大InnoDB Buffer Pool。

查Qcache_lowmem_prunes是否高频增长
这是最直接的信号:只要这个值每分钟涨几百甚至上千,说明查询缓存正在被反复清空,不是内存小,而是机制本身在高并发写入下失效。它和Qcache_inserts比值越高,越证明缓存刚存进去就被踢掉。
执行SHOW STATUS LIKE 'Qcache_lowmem_prunes';,隔10秒再查一次,算差值。若>50/10s,基本可判定Query Cache在制造假缓存、真锁争用。
- 别只看绝对值——要盯住变化速率
- 如果
Qcache_hits极低(比如不到Qcache_inserts的10%),说明命中几乎为零,开它纯属浪费资源 -
Qcache_not_cached高,可能是语句含不确定函数(NOW()、USER())或用了SQL_NO_CACHE,但这不是瓶颈主因
确认query_cache_type是否真失效或被忽略
MySQL 5.7.20起默认禁用,5.7.33+源码已移除Query Cache逻辑——此时query_cache_type变成只读变量,设成1也返回0。别信配置文件里写了query_cache_type = 0就安全了。
登录后立刻执行:SELECT @@query_cache_type;,若返回0,再执行SHOW STATUS LIKE 'Qcache%';。结果为空集(不是数值全0),才说明模块根本没加载。
- 版本≥5.7.33?跳过所有调参,只做禁用动作即可
- 返回1但
Qcache%为空?说明MySQL启动时已跳过初始化,配置无效但变量未同步更新 - 返回1且
Qcache_hits有值?赶紧关,否则全局锁Qcache_lock正在串行化你的查询
观察SHOW PROCESSLIST里有没有卡在Waiting for query cache lock
这是Query Cache拖慢并发最典型的现场证据。一旦出现,意味着当前查询正被缓存模块的全局互斥锁阻塞,后续所有查询都得排队等它释放。
运行SHOW PROCESSLIST;,扫一眼State列。如果看到多行状态是Waiting for query cache lock或Flushing query cache,不用再分析,就是它。
- 临时缓解:执行
FLUSH QUERY CACHE;能整理碎片,但会加更长的锁,生产环境慎用 - 根本解法:永久关闭,避免任何可能触发锁的路径(包括
SQL_CACHE语句) - 注意:这个状态在
information_schema.PROCESSLIST里也能查到,适合脚本监控
禁用后验证Innodb_buffer_pool_wait_free是否上升
关Query Cache的真实收益,是把那把全局锁和内存管理开销让出来,但代价可能是InnoDB Buffer Pool压力变大——尤其原来被Query Cache占着却没用上的那部分内存,现在全压给Buffer Pool了。
重启并禁用后,持续观察Innodb_buffer_pool_wait_free。如果该值明显上升(比如从0飙到每秒几十),说明Buffer Pool内存不足,需要同步调大innodb_buffer_pool_size。
- 建议值:物理内存的50%–75%,例如4GB机器设为2G
- 别只改配置——要配合
SHOW ENGINE INNODB STATUS\G里的Buffer pool hit rate看实际效果 - 如果
Innodb_buffer_pool_reads仍很高,说明数据还在频繁刷盘,Buffer Pool还没真正“接住”流量
真正卡住高并发的,往往不是缓存没命中的失落感,而是那把谁都绕不开的Qcache_lock。它不声不响,却让所有查询排成一队。











