mysql 8.0 启动报 unknown system variable 'query_cache_type' 是因该变量已被代码级删除,必须彻底删除配置文件中所有以 query_cache_ 开头的行(含注释),否则服务无法启动;其底层全局锁、表级失效机制及字节级匹配等设计缺陷导致高并发下性能反降,故被永久移除。

MySQL 8.0 启动报 Unknown system variable 'query_cache_type' 怎么办
这不是配置写错了,是变量本身已不存在。MySQL 8.0.3 起,整个 Query Cache 模块被物理移除,解析器连识别都做不到。
必须手动删除 my.cnf(或 my.ini)中所有以 query_cache_ 开头的行,包括注释掉的也得删干净——留一行,mysqld 就起不来。
- Percona Server 8.x、MariaDB 10.6+ 同样不兼容,别指望降级兼容
- 云数据库(如 RDS)若使用自定义参数组,同样要检查并移除残留项
- Docker 镜像若沿用旧配置模板,也会卡在这一步,得重写配置
为什么 SELECT 查询总卡在 Waiting for query cache lock
因为 Query Cache 底层用的是单点全局锁 LOCK_query_cache,所有读写操作(查、存、清)都得抢它。
哪怕只是检查 SELECT * FROM users WHERE id = 123 在不在缓存里,也得排队等锁。多核服务器上,几十个并发 SELECT 会集中阻塞在锁上,CPU %system 异常升高。
-
SHOW PROCESSLIST里大量线程显示Waiting for query cache lock,就是典型征兆 - 这个锁和 InnoDB 行锁完全不在一个量级——无法分片、不能降级、不可绕过
- 它不是“偶尔争抢”,而是每次缓存路径访问必走,哪怕
query_cache_size = 0,判断逻辑仍存在、锁仍要抢
为什么 UPDATE 一行就让整张表的查询缓存全失效
Query Cache 的失效粒度是表级(table-level),不是语句级或行级,且清空过程本身还要持锁。
UPDATE users SET name='x' WHERE id=1 一执行,所有命中 users 表的缓存(不管 SQL 多具体)立刻被扔掉。缓存刚建好,下一秒就被清空,变成“临时工式缓存”。
- 事务未提交时缓存已失效,但新查询又不能读未提交数据,出现“失效了却还不能用”的真空
- 分区表默认禁用查询缓存,而生产环境大表基本都分区——说明设计早已脱离实际
- 预处理语句(
PREPARE/EXECUTE)、含NOW()、用户变量、子查询的查询,一律不进缓存路径
为什么缓存命中率长期低于 0.1 却还在消耗资源
命中条件苛刻到近乎不可用:SQL 必须字节级一致,且大量常见语句直接被跳过。
SELECT id FROM t WHERE x=1 和 SELECT id FROM t WHERE x = 1 是两个 key(空格差一点就不行);现代 ORM 几乎全走预处理,这类查询根本不会触发缓存路径。
-
Qcache_hits / (Qcache_hits + Qcache_inserts)常低于 0.1,意味着每 10 次 SELECT 只有不到 1 次命中 -
query_cache_size分配的是静态连续大块内存,不归innodb_buffer_pool_size管理,无法复用 - 缓存结果集为 1KB,却按
query_cache_min_res_unit(默认 4KB)硬切,浪费明显 - InnoDB Buffer Pool 已通过页级缓存、自适应 LRU-K、动态调整,更省内存、更准、更可控
真正容易被忽略的一点是:你升级后还在日志里搜 Qcache_hits,或盯着慢查分析缓存效果——这些指标在 MySQL 8.0 里压根不存在了,它们只会让你误判问题根源。











