MySQL 8.0 彻底移除了 Query Cache 功能,相关配置项(如 query_cache_type)已从源码删除,启动时会因未知变量报错;其被删除主因是全局锁、表级失效、低命中率等根本性设计缺陷。

MySQL 8.0 中根本没有 Query Cache 这个功能——不是“关了”,是代码里删干净了,配置即报错,启动直接失败。
query_cache_type 配置一写就启动失败
从 MySQL 8.0.3 起,query_cache_type、query_cache_size、query_cache_limit 等所有相关变量已从源码中彻底移除。mysqld 解析配置时根本不认识它们:
- 在
my.cnf里写query_cache_type = 0,服务拒绝启动,报错Unknown system variable 'query_cache_type' - 云数据库(如 RDS)、Docker 镜像、Percona Server 8.x、MariaDB 10.6+ 同样不识别,别指望兼容
- 升级前必须手动删掉所有以
query_cache_开头的配置行,否则卡在启动阶段
为什么不是禁用,而是物理删除?
Query Cache 的问题不是调参能修的,它的设计缺陷嵌在执行路径最底层:
-
LOCK_query_cache是全局互斥锁:每次 SELECT 检查缓存、UPDATE 清缓存、甚至FLUSH QUERY CACHE整理碎片,都得抢这把锁——多核机器上,几十个并发查询全堵在锁上 - 失效粒度是表级的:一次
UPDATE user SET name='x' WHERE id=123,所有命中user表的缓存(不管 SQL 多长、是否带 LIMIT)全部清空,且清空过程也持锁 - 命中条件苛刻到失效:SQL 必须字节级一致,
SELECT * FROM t和select * from t是两个 key;含NOW()、@var、预处理语句(PREPARE/EXECUTE)的查询直接绕过缓存 - 内存管理反成负优化:
query_cache_size是静态大块连续内存,碎片严重时查找比执行原 SQL 还慢;这部分内存不归innodb_buffer_pool_size管,纯属额外开销
Qcache_hits / Com_select 比值长期低于 0.1 就该警觉
官方实测和大量生产监控显示,真实 OLTP 场景下缓存命中率常低于 5%。但代价始终在线:
- 每条 SELECT 都要走一遍缓存判断逻辑(即使你设了
query_cache_size = 0,路径仍存在) - CPU 开销随并发线程数线性上升,实测开启后 CPU usage 升高 13%~18%
- 分区表默认禁用查询缓存,而生产环境大表基本都分区——意味着你白配了
- 它和 InnoDB 的 MVCC 冲突:为保“语句级强一致性”,牺牲所有并发可扩展性
替代方案不是“找个新开关”,而是换位置、换粒度、换控制权
MySQL 8.0 把资源让给更可控、更高频复用的机制:
- 应用层缓存优先用
Redis或Memcached:能定义 TTL、支持复合 key、可共享、还能做热点穿透保护 - 专注调优
innodb_buffer_pool_size:它缓的是数据页,不是结果集,读写混合下命中率高得多,且无锁争用 - 连接层用
ProxySQL做 SQL 哈希缓存:支持规则匹配、TTL 控制、失效策略更细粒度 - 避免写天然反缓存的 SQL:
SELECT *、ORDER BY RAND()、没覆盖索引的分页查询
最容易被忽略的一点:Query Cache 的“缓存收益”其实是假象——它省下的解析时间,远低于它引入的锁竞争、内存碎片和 CPU 开销。真正该盯紧的,是 innodb_buffer_pool_hit_ratio 和慢查询里那些没走索引的 SELECT。











