mysql 8.0 彻底移除查询缓存模块,启动时遇到 querycache* 配置直接报错退出;其全局锁、表级失效、字节级匹配等设计导致实际命中率极低,且与 innodb 缓存冲突,删除相关配置是必要升级步骤。

MySQL 8.0 不是“禁用了”查询缓存,而是从源码里彻底删掉了整个 Query Cache 模块——所有相关变量、状态、逻辑路径全都不复存在。你写 query_cache_type = 0 或任何 query_cache_* 配置,mysqld 启动时直接报错退出,不是警告,不是忽略,是拒绝启动。
my.cnf 里还留着 query_cache_* 就起不来服务
这是升级后最常踩的坑:从 5.7 升级到 8.0,配置文件没清理,mysqld 日志里明确打出 Unknown system variable 'query_cache_type' 或 Unknown variable 'query_cache_size',然后进程终止。Percona Server 8.x、MariaDB 10.6+ 同样不兼容,别指望“向下兼容”。
- 必须手动删除
my.cnf(或my.ini)中所有以query_cache_开头的行,包括注释掉的也得删干净 - 云数据库(如 RDS)若使用自定义参数组,同样要检查并移除残留项
- docker 镜像若沿用旧配置模板,也会卡在这一步,得重写配置
LOCK_query_cache 全局锁让并发查询排队等死
Query Cache 的底层是一个全局哈希表,所有访问(查、写、清)都得抢同一把互斥锁 LOCK_query_cache。哪怕只是检查 SELECT * FROM users WHERE id = 123 在不在缓存里,也得排队等锁。
- 多核机器上,几十个并发 SELECT 不是并行执行,而是在锁上排队,
CPU %system异常升高 -
SHOW PROCESSLIST里大量线程显示Waiting for query cache lock - 这个锁和 InnoDB 行锁完全无关,无法分片、无法降级,是单点瓶颈
表级失效 + 字节级匹配 = 实际业务中几乎零命中
一次 UPDATE users SET name='x' WHERE id=123,会立刻清空 users 表下所有缓存条目:不管 SQL 多长、是否带 LIMIT、是否只查一个字段,全扔掉。同时,缓存键要求 SQL 字符串**字节级一致**。
- ORM 生成的语句带随机空格、注释、参数占位符(如
WHERE id = ?),根本不会进缓存路径 -
SELECT id FROM t WHERE x=1和SELECT id FROM t WHERE x = 1是两个 key - 含
NOW()、用户变量、子查询、分区表的查询,全部被跳过 - 实测生产环境
Qcache_hits / Com_select普遍低于 0.1,缓存成了“开销税”
内存管理反成负优化,且与 InnoDB Buffer Pool 冲突
query_cache_size 分配的是静态连续大块内存,不归 innodb_buffer_pool_size 管理,无法复用。碎片严重时,FLUSH QUERY CACHE 自身就要持锁、吃 CPU。
- 缓存结果集为 1KB,却按
query_cache_min_res_unit(默认 4KB)硬切,浪费明显 - 没有 LRU、TTL、冷热分离,失效策略粗暴,无法适配真实访问模式
- InnoDB Buffer Pool 已通过页级缓存、自适应 LRU-K、动态调整,更省内存、更准、更可控
真正容易被忽略的,是那些还活在旧文档、配置模板、自动化部署脚本里的 query_cache_* 行——它们不会报错直到你升级那一刻。删掉它们,不是少了个功能,而是卸下了个常年拖慢并发、偷偷吃 CPU、还假装在工作的负担。











