mysql 8.0+ 已彻底移除查询缓存模块,query_cache_type等所有相关变量被代码级删除,配置即报错;应删除my.cnf中所有query_cache_配置项,并转向应用层缓存、innodb缓冲池优化等替代方案。

MySQL 8.0 启动就报 Unknown variable 'query_cache_type'
这不是配置写错了,是 MySQL 8.0.3 起直接删掉了整个 Query Cache 模块。所有相关变量——query_cache_type、query_cache_size、query_cache_limit——全被移除,连解析器都不认识它们。
如果你从 5.7 升级上来,my.cnf 里只要残留任意一个 query cache 配置项,mysqld 就无法启动,错误信息可能卡在日志末尾,也可能直接退出。Percona Server 8.x 和 MariaDB 10.6+ 同样不兼容,别指望“向后兼容”。
解决方式只有一条路:彻底删掉配置文件中所有以 query_cache_ 开头的行,再重启服务。
明明是 MySQL 5.7,SHOW VARIABLES LIKE 'query_cache%' 却显示 size=0、type=0
MySQL 5.6 起默认就把 query_cache_type = 0 写进源码了,5.7 官方文档明确标注为 deprecated,且默认关闭。即使你手动设成 1,只要实例有哪怕轻微写入(比如慢日志记录、监控探针 UPDATE),缓存就会高频失效,Qcache_lowmem_prunes 和 Qcache_hits 的比值往往低于 0.1,实际等于没开。
验证是否真在工作,不能只看变量,得查运行时状态:
- 执行
SELECT SQL_NO_CACHE COUNT(*) FROM information_schema.TABLES后,再执行同语句不带SQL_NO_CACHE,观察Qcache_hits是否增加 - 检查
Qcache_inserts和Qcache_queries_in_cache是否长期为 0 或极低 - 如果
Qcache_lowmem_prunes > 0持续上涨,说明缓存块刚写进去就被踢出,内存管理已失衡
为什么 SELECT * FROM t WHERE id = 1 缓存不了或总 Miss
Query Cache 的匹配是字面级的:大小写、空格、注释、换行、客户端连接参数(如 sql_mode)稍有不同,哈希值就变,缓存完全不复用。ORM 自动生成的 SQL 很难满足这个条件。
更关键的是,以下情况直接跳过缓存,连尝试都不做:
- 语句含
NOW()、RAND()、CURRENT_USER()、@var等非确定性成分 - 查了临时表、系统表(如
mysql.user)、MEMORY 引擎表 - 用了子查询、UNION、视图、存储函数
- 结果集超过
query_cache_limit(默认 1MB) - 表被任何线程执行过
INSERT/UPDATE/DELETE,整张表所有缓存瞬间清空
现在该用什么替代 Query Cache
不是“没了就得硬扛”,而是把缓存放到更可控的位置:
- 应用层用
Redis或Memcached:能按业务语义构造 key,支持 TTL、穿透保护、批量失效 - 调优
innodb_buffer_pool_size:它缓的是数据页,不是结果集,读写混合下命中率稳定得多 - 代理层加
ProxySQL:支持基于表名、用户、正则等规则的结果集缓存,粒度远细于原生 Query Cache - SQL 层面避免反模式:少用
SELECT *、加覆盖索引、去掉ORDER BY RAND()这类天然不可缓操作
真正容易被忽略的一点:Query Cache 的全局锁(LOCK_query_cache)在多核机器上会成为并发瓶颈,而 InnoDB Buffer Pool 是分段锁,Redis 是单线程但无锁竞争——替换不是为了“加功能”,是为了去掉那个深入骨髓的设计缺陷。











