MySQL 5.7中query_cache_type=1会引发全局query_cache_lock争抢,造成串行瓶颈;应彻底禁用查询缓存,转而优化innodb_buffer_pool_size以提升性能。

query_cache_type=1 会引发全局锁争抢
MySQL 5.7 中只要 query_cache_type=1 且 query_cache_size 非零,所有 SELECT 就必须抢同一把 query_cache_lock 互斥锁。这不是并发优化,是串行瓶颈。
常见错误现象包括:perf top -p $(pgrep mysqld) 频繁出现 query_cache_lock 符号;SHOW STATUS LIKE 'Qcache_lowmem_prunes' 远高于 Qcache_hits;Threads_connected 持续上涨但 Queries QPS 不增反降。
写操作(哪怕只是 INSERT INTO audit_log)会触发全表缓存清空,导致缓存命中率长期低于 5%。InnoDB 表每秒几条 DML,就足以让缓存逻辑变成负收益。
哪些查询根本不会进缓存,你可能根本不知道
即使参数全开,以下情况直接跳过缓存逻辑,连尝试都不做:
- SQL 文本含任意空格、换行、注释或大小写差异:
SELECT id FROM t和SELECT id FROM t ;视为不同语句 - 用了非确定性函数:
NOW()、RAND()、UUID()、CURRENT_USER() - 含用户变量:
SELECT @x := 1或子查询里引用@var - 访问系统库:
information_schema、performance_schema、mysql - 结果集超过
query_cache_limit(默认 1MB) - 语句显式加了
SQL_NO_CACHE
这意味着:只要 ORM 拼出的 SQL 带一个 NOW(),整条查询就永远不可能命中——你查 Qcache_hits 都是白费劲。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
永久关闭比调优更安全有效
别调 query_cache_size 或 query_cache_min_res_unit,这些参数治标不治本,还掩盖真实瓶颈。正确做法是彻底禁用:
- 编辑
my.cnf,在[mysqld]段中删掉或注释掉所有query_cache_*行:query_cache_type、query_cache_size、query_cache_limit、query_cache_min_res_unit - 必须重启
mysqld(systemctl restart mysqld),仅 reload 配置不生效 - 确认
SHOW VARIABLES LIKE 'query_cache%'全部返回OFF或0
注意:SET GLOBAL query_cache_type = OFF 只是临时停用,MySQL 重启后仍会读取配置文件里的残留参数——只要 query_cache_size 不为 0,5.7 就认定“你要用”,并加载锁机制。
真正该投入精力优化的是 innodb_buffer_pool_size
查询缓存被移除不是性能倒退的根源,而是把问题暴露出来。InnoDB Buffer Pool 才是现代 MySQL 的核心缓存层:
-
innodb_buffer_pool_size应设为物理内存的 50%–75%,且必须启用innodb_buffer_pool_instances(建议设为 CPU 核数)以减少内部争用 - 监控命中率:
(1 - Innodb_buffer_pool_reads / Innodb_buffer_pool_read_requests) * 100%,理想值 > 95% - 若命中率低,优先检查慢查询是否引发全表扫描,而非回头想“要不要开查询缓存”
最易被忽略的是:5.7.20+ 版本里 query_cache_type 已被标记为 deprecated,5.7.33+ 和全部 8.0 版本已彻底移除代码路径——你看到的变量还在,只是入口函数已被绕过。验证是否真失效,得看 SHOW STATUS LIKE 'Qcache_hits' 是否增长,而不是信 SHOW VARIABLES 的返回值。










