MySQL 8.0 已彻底移除 query_cache_type 等所有查询缓存变量,必须从 my.cnf 中完全删除相关配置行才能启动;其失效机制为表级粗粒度、全局锁争用严重,高并发下反而降低 QPS,官方已弃用,推荐改用应用层缓存、InnoDB Buffer Pool 或 ProxySQL 等替代方案。

MySQL 8.0 启动就报 Unknown system variable 'query_cache_type' 怎么办
这不是配置写错了,是变量真没了。MySQL 8.0 已从源码中彻底删除 query_cache_type、query_cache_size、query_cache_limit 所有相关变量。你在 my.cnf 里留着它们,mysqld 就会启动失败,报错退出。
解决方法只有一条:删掉所有以 query_cache_ 开头的配置行,重启服务。别设成 0,别加注释,直接删——它已经不是“关闭”,而是“不存在”。
为什么 UPDATE 一次就让整张表的 SELECT 缓存全失效
Query Cache 的失效逻辑是表级粗粒度的:只要对 users 表执行任意 INSERT/UPDATE/DELETE,所有命中该表的缓存条目(无论 SQL 多具体)立刻清空。
-
SELECT name FROM users WHERE id = 1和SELECT COUNT(*) FROM users会被同一行UPDATE干掉 - 事务还没提交,缓存已失效;但新查询又不能读未提交数据,形成“失效了却还不能用”的真空
- 分区表默认禁用 Query Cache,而生产环境大表基本都分区——这说明它的设计早已脱离主流用法
为什么高并发下 Query Cache 反而拖慢 QPS
核心瓶颈是那把全局锁 LOCK_query_cache:所有 SELECT 检查缓存、所有 DML 清空缓存,都得排队等它。
- 几十个并发 SELECT 一上来就卡在锁上,CPU 花在调度等待的时间远超执行 SQL
- 哪怕只改一行,
UPDATE users SET updated_at = NOW() WHERE id = 123也会触发整张表缓存重建 + 全局锁持有 - Percona 实测:200+ QPS 写入场景下,开启 Query Cache 的吞吐比关闭时低 15%~30%
-
SHOW PROCESSLIST里大量出现Waiting for query cache lock
替代方案不是“换个开关”,而是换思路
MySQL 8.0 没提供内置替代品,因为官方认为:靠 SQL 文本哈希匹配的结果集缓存,本身就不适配现代 OLTP 场景。
- 应用层缓存(Redis):对字典表、配置项这类低频更新高频率读的数据,用业务可控的 key 和 TTL
- InnoDB Buffer Pool:调大
innodb_buffer_pool_size,它缓的是数据页,支持并发读、MVCC、LRU 淘汰,无全局锁 - 代理层缓存(ProxySQL):在连接池侧做 SQL 哈希缓存,可设 TTL、按库/表粒度失效,不干扰 MySQL 内核
- 物化视图(
CREATE TABLE AS SELECT+ 定时刷新):适合稳定聚合查询,比 Query Cache 更可靠
最容易被忽略的一点:Query Cache 存在时,DBA 看到 Qcache_hits 很低,第一反应是“调大缓存”,却没意识到——那把锁正在 silently 把并发能力吃掉。


















