MySQL 8.0 彻底移除了 query_cache 相关参数,配置中保留任一 query_cache 变量将导致启动失败;其性能缺陷源于低命中率与全局锁争用,官方转而推荐应用层缓存、InnoDB Buffer Pool 等更优替代方案。

MySQL 8.0 启动就报 Unknown variable 'query_cache_type=1'
这不是配置没生效,是代码里真删了。只要 my.cnf 或 mysqld-auto.cnf 里还留着 query_cache_type、query_cache_size、query_cache_limit 中任意一个,mysqld 就会启动失败,直接退出。错误信息明确指向变量名不存在——不是弃用警告,是彻底移除。
5.7 虽然默认 query_cache_type = OFF,但参数仍存在,能配、能查、能改。很多运维习惯性保留这些配置项,升级到 8.0 后才发现服务起不来。重点检查:SELECT VARIABLE_NAME, VARIABLE_SOURCE FROM performance_schema.variables_info WHERE VARIABLE_NAME LIKE 'query_cache%';,结果为空才说明干净。
5.7 里开着 query_cache 反而拖慢 QPS 的真实原因
缓存命中率低 + 单锁争用,是性能倒退的根源。比如压测时 Qcache_hits 是 1523,Qcache_inserts 是 98234,命中率仅 1.5%,但每次 SELECT 都要抢同一把全局互斥锁去查哈希表、判断失效、写入新结果——这部分开销白花了。
- 任何对表的 INSERT/UPDATE/DELETE 都会让该表所有缓存条目立即失效(哪怕事务未提交)
- SQL 必须字节级一致才能命中:
SELECT * FROM t≠select * from t≠SELECT * FROM t -- comment - 含
NOW()、RAND()、用户变量@var、临时表的查询一律不缓存
所以它只在极窄场景有效:纯只读库 + 固定 SQL 模板 + 结果集小 + 更新间隔远大于查询频率。现实中这类系统越来越少。
8.0 不是“没了缓存”,而是换到了更可控的位置
官方放弃的是数据库内核层的通用结果缓存,不是放弃缓存本身。替代路径非常明确:
- 应用层用
Redis或Memcached缓存结构化结果(例如SELECT id,name FROM user WHERE status=1),由业务控制过期逻辑 - InnoDB Buffer Pool 承担数据页缓存,
innodb_buffer_pool_size应设为物理内存的 50%–75%,且必须配innodb_buffer_pool_instances > 1减少内部争用 - 高频只读视图可物化:定时写入临时表,应用层查表而非实时计算
- 用
ProxySQL做中间层缓存,支持正则匹配、权重路由、细粒度失效,实测吞吐和命中率远超原生 query_cache
这些方案不共享 MySQL 内核锁,可独立伸缩,缓存策略也更贴近业务语义。
升级后慢查询暴增,大概率不是因为“没了缓存”
真正踩坑点藏在三个地方:
-
persisted_variables覆盖 my.cnf:执行过SET PERSIST sort_buffer_size = 64K的实例,改了配置文件也不生效,得先RESET PERSIST;再重启 - 统计信息过期:
INNODB_TABLESTATS.last_update还停在 5.7 时代,导致优化器误判行数,跳过索引走全表扫描——立刻跑ANALYZE TABLE your_table; -
optimizer_switch默认值变更:比如mrr=off(5.7 是 on)、index_merge=on(可能拼凑单列索引反而比复合索引慢),用EXPLAIN FORMAT=TREE对比执行计划差异
query_cache 的移除只是个引子,它暴露的是旧配置、旧习惯、旧评估方式在新版本下的不兼容。盯着缓存本身,反而会漏掉真正要调的参数。


















