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_type、query_cache_size、query_cache_limit 全部不复存在,mysqld 解析器根本无法识别它们。服务会直接拒绝启动,并在错误日志里明确打出该报错。
- 必须手动删掉
my.cnf(或my.ini)里所有以query_cache_开头的行,包括注释掉的也得清理干净 - Percona Server 8.x、MariaDB 10.6+、云数据库(如 RDS)、Docker 镜像若沿用旧参数模板,同样会卡在这一步
- 别试图设成
0或OFF—— 它不是开关,是“没这个东西”
LOCK_query_cache 全局锁让并发查询排队等死
Query Cache 的底层是一个单点全局哈希表,所有操作(查是否存在、写入结果、清空条目)都必须抢同一把互斥锁 LOCK_query_cache。哪怕只是检查 SELECT * FROM users WHERE id = 123 是否命中,也得排队等锁。
- 多核服务器上,几十个并发 SELECT 不是并行执行,而是在锁上排队,
%systemCPU 异常升高 -
SHOW PROCESSLIST中大量线程显示Waiting for query cache lock - UPDATE 清缓存的过程本身也要持锁,进一步延长阻塞时间
- 这个锁和 InnoDB 行锁完全无关,无法分片、无法降级,是硬编码死结
表级失效 + 字节级匹配 = 实际业务中几乎零命中
一次 UPDATE users SET name='x' WHERE id=123,会立刻清空 users 表下所有缓存条目:不管 SQL 多长、是否带 LIMIT、是否只查一个字段,全扔掉。同时,缓存键要求 SQL 字符串字节级一致。
-
SELECT id FROM t WHERE x=1和SELECT id FROM t WHERE x = 1(空格差一点)就是两个 key - ORM(如 MyBatis、Hibernate)生成的语句含随机占位符、注释、换行,基本不进缓存
- 含
NOW()、@var、预处理语句、子查询、分区表的查询,一律被跳过 - 实测生产环境
Qcache_hits / Com_select普遍低于 0.1,缓存成了“开销税”
内存管理反成负优化,且与 innodb_buffer_pool_size 冲突
query_cache_size 分配的是静态连续大块内存,不归 innodb_buffer_pool_size 管理,无法复用。碎片严重时,FLUSH QUERY CACHE 自身就要持锁、吃 CPU。
- 缓存结果集为 1KB,却按
query_cache_min_res_unit(默认 4KB)硬切,浪费明显 - 哈希表碰撞多、碎片化严重时,查找缓存本身比执行原 SQL 还慢
- InnoDB Buffer Pool 已通过页级缓存 + LRU-K 实现更细粒度、更高命中率的数据访问优化
- Buffer Pool 可动态调整,支持自适应淘汰策略;Query Cache 没有 TTL、没有访问频次淘汰逻辑
真正容易被忽略的是:Query Cache 的存在,会让问题排查跑偏——看到命中率低,第一反应是调参,而不是意识到它本就不该出现在现代 OLTP 架构里。











