mysql 8.0 彻底删除 query cache 模块,非禁用而是源码级移除,配置即报错退出;因其全局锁(lock_query_cache)导致高并发排队、表级失效引发命中率长期低于5%、字节级匹配与现代orm/预处理不兼容,且开销反超收益,故让位于 innodb buffer pool 和应用层缓存等更高效方案。

MySQL 8.0 取消 Query Cache 不是“去掉一个功能”,而是移除了一个在高并发下持续抢锁、频繁失效、还吃内存的全局瓶颈——系统反而更稳、吞吐更高。
query_cache_type 配置一写就报错,不是配错了,是彻底没了
MySQL 8.0 源码里已删掉所有 query_cache_* 相关逻辑。你在 my.cnf 里写 query_cache_type = 0 或 query_cache_size = 16M,mysqld 启动时直接报 Unknown variable 'query_cache_type' 并退出。这不是配置项被“默认关闭”,是变量名本身已被编译器剔除。
Percona Server 8.x 和 MariaDB 10.6+ 同样不兼容。别试图注释掉再试——删干净配置项才是唯一解。
LOCK_query_cache 全局锁让并发 SELECT 排队卡死
Query Cache 的所有路径(查缓存、写缓存、清缓存)都必须争抢同一个互斥锁 LOCK_query_cache。这个锁不分读写、不可降级、无法分片。
- 哪怕只是检查
SELECT * FROM users WHERE id = 123在不在缓存里,也要排队等锁 - 一次
UPDATE users SET name='x' WHERE id=123,不仅清空该语句缓存,还要持锁清掉整张users表所有缓存条目 - OLTP 场景下,几十个并发 SELECT 线程全卡在锁上,CPU 花在上下文切换,而不是执行 SQL
实测显示:200+ QPS 写入时,开启 Query Cache 的吞吐比关闭时低 15%~30%。
缓存命中率长期低于 5%,但开销始终在线
Query Cache 要求 SQL 字节级完全一致:空格、换行、大小写、注释、客户端字符集、SQL mode 差一点,就是不同 key。
- ORM(Django/MyBatis/Sequelize)生成的语句天然带随机空格和注释,基本不命中
-
PREPARE/EXECUTE预处理语句根本绕过 Query Cache 路径 - 含
NOW()、RAND()、用户变量、子查询带临时表的语句,直接被拒 - 分区表默认禁用 Query Cache,而生产环境大表基本都分区
结果就是:Qcache_hits / Com_select 比值常年低于 0.1,缓存几乎形同虚设,但内存碎片整理、哈希计算、全局查找这些 CPU 开销照常发生——实测 CPU usage 升高 13%~18%。
资源让给了真正可扩展的机制
删掉 Query Cache 不是放弃缓存,而是把内存、CPU、锁管理逻辑腾出来交给更可控的组件:
-
innodb_buffer_pool_size成为唯一核心缓存开关:它缓存的是页(page),不是结果集;支持并发读、MVCC、LRU-K 淘汰,且无全局锁 - 应用层缓存(Redis/Memcached)由业务控制生命周期:可按 key 粒度失效、支持 TTL、能穿透更新
- 物化视图(
CREATE TABLE AS SELECT+ 定时刷新)更适合稳定聚合场景,比 Query Cache 更可靠
最容易被忽略的一点:Query Cache 的存在,会让 DBA 误判性能问题根源——看到 Qcache_hits 很低,第一反应是“调大 query_cache_size”,却忽略了 innodb_buffer_pool_size 是否合理、慢查询是否漏了索引、连接池是否在反复建连。











