mysql 8.0 彻底移除查询缓存模块,相关配置(如 query_cache_type)启动即报错;全局锁导致高并发下严重排队;表级失效与字节级匹配使命中率极低;内存管理低效且与 innodb 缓冲池冲突。

MySQL 8.0 不是“关掉了”查询缓存,而是从源码里彻底删掉了整个 Query Cache 模块——你写任何 query_cache_* 配置,mysqld 启动直接报错退出,服务起不来。
启动报 Unknown system variable 'query_cache_type' 怎么办
这不是配置写错了,是变量本身已不存在。MySQL 8.0.3 起,所有 query_cache_type、query_cache_size、query_cache_limit 等相关逻辑全被物理移除,解析器连识别都做不到。
- 必须手动删除
my.cnf(或my.ini)中所有以query_cache_开头的行,包括注释掉的也得删干净 - Percona Server 8.x、MariaDB 10.6+ 同样不兼容,别指望降级兼容
- 云数据库(如 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 字符串**字节级一致**。
-
SELECT id FROM t WHERE x=1和SELECT id FROM t WHERE x = 1是两个 key(空格差一点就不行) - 含
NOW()、RAND()、用户变量、子查询、分区表的查询,全部被跳过 - 预处理语句(
PREPARE/EXECUTE)根本不会进入缓存路径,现代 ORM 几乎全走这条路 - 实测生产环境
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)硬切,浪费明显 - 没有 LRU、TTL、冷热分离,失效策略粗暴,无法适配真实访问模式
- InnoDB Buffer Pool 已通过页级缓存、自适应哈希、LRU-K 等机制实现更细粒度、更高命中率的数据访问优化
- 这部分内存纯属额外占用,且和 MVCC 机制存在一致性冲突
真正容易被忽略的是:哪怕你把 query_cache_size = 0,只要模块还在,每次 SELECT 仍要走一遍缓存判断逻辑——这个路径在 8.0 里已彻底消失,不是“省了开关成本”,是连判断动作都没了。











