mysql 8.0 彻底移除查询缓存模块,query_cache_size等所有相关变量已从源码中删除,配置即报错;替代方案为应用层缓存、代理层缓存或innodb缓冲池优化。

MySQL 8.0 中 query_cache_size 直接报错:Unknown system variable
执行 SHOW VARIABLES LIKE 'query_cache%'; 后返回空或报错,不是配置写错了,是 MySQL 8.0 彻底移除了 Query Cache 模块。所有相关变量(query_cache_type、query_cache_size、query_cache_limit)均已不存在。试图在配置文件里写入这些参数,mysqld 启动时会忽略或报错退出。
这不是“默认关闭”,而是代码级删除——源码中已无 Query Cache 的任何逻辑分支。如果你从 5.7 升级到 8.0 后发现缓存没生效,别调参,先确认版本是否真为 8.0+。
为什么 UPDATE user SET name='a' WHERE id=1 能让整个用户表的查询缓存全失效
Query Cache 的失效机制是表级粗粒度的:只要某张表发生任意 DML 或 DDL 操作,所有命中该表的缓存条目(无论 SQL 多具体、结果集多小)都会被立即清除。这导致两个现实问题:
- 高并发写场景下,缓存命中率趋近于零——哪怕只有一条更新语句,就可能清掉上千个 SELECT 缓存
- 无法区分“影响行数”:
UPDATE ... LIMIT 1和UPDATE ... WHERE status=0在缓存层面待遇完全一样 - 事务未提交时缓存已失效,但新查询又不能读到未提交数据,造成“失效了却还不能用”的真空状态
这种设计在单核低并发时代尚可容忍,在现代多核、混合负载的 OLTP 系统中,反而成了性能瓶颈放大器。
替代方案不是“找个新缓存开关”,而是换思路
MySQL 8.0 并没有提供内置替代品,因为官方认为:靠 SQL 文本匹配的全局结果缓存本身就不适配当前硬件与业务模型。真正有效的替代路径有三条:
- 应用层缓存:对确定性高、变化少的查询(如配置表、地区字典),用 Redis 缓存序列化结果,由业务控制 key 生效逻辑和失效时机
- 代理层缓存:用 ProxySQL 或 MaxScale,在连接池层做 SQL 哈希匹配缓存,支持更灵活的 TTL 和失效策略,且不干扰 MySQL 内核
-
InnoDB 层优化:把精力放在
innodb_buffer_pool_size调优、索引覆盖、自适应哈希(innodb_adaptive_hash_index)上——Buffer Pool 缓的是数据页,复用率远高于结果集,且无锁争用问题
注意:不要试图用 CACHE hint 或临时表模拟查询缓存,它们无法解决根本的并发失效和内存碎片问题,反而增加解析开销。
最容易被忽略的点:缓存收益 ≠ 查询加速
Query Cache 的原始目标是降低 CPU 消耗,但它在实际中常带来三重隐性成本:
- 每次 SELECT 前要加全局锁检查缓存,写多时这个锁比执行 SQL 还抢资源
- 缓存结果集是完整拷贝,大结果(比如
SELECT * FROM log_table LIMIT 10000)会迅速吃光query_cache_size并引发频繁碎片整理 - 它掩盖了真正的性能问题:一个本该走索引的慢查,在缓存命中时“看起来快”,一旦缓存失效就暴露原形,导致问题延迟发现
MySQL 团队移除它的真正意图,不是放弃缓存,而是逼你面对查询本身的质量——缓存不该是补丁,而是锦上添花。











