MySQL 8.0.3+ 已彻底移除 Query Cache 模块,需删除配置中所有 query_cache_ 开头的行(含注释)、清空 persisted_variables,并更新 Docker/RDS 参数模板;其表级失效、全局锁、低命中率及高资源消耗导致性能反降,移除后由 InnoDB Buffer Pool、应用层缓存等更优机制替代。

MySQL 8.0 启动报 Unknown system variable 'query_cache_type' 怎么办
这不是配置写错了,是变量名本身已被编译器剔除。MySQL 8.0.3 起,整个 Query Cache 模块从源码中物理删除,mysqld 解析器根本识别不了 query_cache_type、query_cache_size、query_cache_limit 等任何以 query_cache_ 开头的配置项——留一行,服务就启动失败。
必须手动清理:
- 删掉
my.cnf(或my.ini)里所有以query_cache_开头的行,包括被#注释掉的也得删干净 - 检查
performance_schema.persisted_variables,用RESET PERSIST;清掉可能残留的持久化设置 - Docker 或云数据库(如 RDS)若复用旧参数组,同样要同步更新配置模板,否则容器卡在启动阶段
为什么 UPDATE 一行就清空整张表所有查询缓存
Query Cache 的失效粒度是表级(table-level),不是语句级或行级。哪怕执行的是 UPDATE users SET name='Alice' WHERE id=123,所有命中 users 表的缓存条目——不管 SQL 多具体、是否带 LIMIT、是否只查一个字段——全部被立即标记为失效。
更关键的是,这个清空动作本身要抢全局锁 LOCK_query_cache:
- 清缓存期间,所有新进来的 SELECT(无论是否涉及
users表)都得排队等待 - 事务未提交时缓存已失效,但新查询又不能读未提交数据,形成“失效了却还不能用”的真空
- 分区表默认禁用 Query Cache,而生产环境大表基本都分区,说明该机制早已脱离主流用法
为什么缓存命中率长期低于 0.1 却还在吃资源
命中条件苛刻到近乎不可用:SQL 必须字节级完全一致,且大量常见语句被直接跳过。
-
SELECT id FROM t WHERE x=1和SELECT id FROM t WHERE x = 1(空格差一点)就是两个 key - 预处理语句(
PREPARE/EXECUTE)、含NOW()、RAND()、用户变量、子查询、视图的查询,一律不进缓存路径 - 内存按
query_cache_min_res_unit(默认 4KB)硬切,缓存结果集仅 1KB 也要占 4KB,碎片严重时FLUSH QUERY CACHE自身就要持锁、吃 CPU - 实测显示:Qcache_hits / Com_select 比值常年低于 0.1,但 CPU usage 反而升高 13%~18%
移除 Query Cache 后性能反而提升的底层原因
删掉 Query Cache 不是放弃缓存,而是把资源让给真正可扩展的机制:
- InnoDB Buffer Pool 已能高效缓存热数据页,且无全局锁开销
- 应用层缓存(如 Redis、MyBatis 二级缓存)更灵活,支持语义等价、参数化、TTL 控制
- 优化器在 8.0 中更依赖统计信息和索引选择,
ANALYZE TABLE和innodb_stats_persistent = ON比调query_cache_size有效得多 - 第三方代理(如 ProxySQL)可做语句级缓存,支持模糊匹配、权重路由,且不污染 MySQL 内核
真正容易被忽略的点是:升级后性能下降,往往不是因为缓存没了,而是 optimizer_switch 默认值变了、统计信息没刷新、persisted_variables 覆盖了配置——这些比找“替代 query_cache 的方案”更优先要处理。


















