MySQL 8.0 已彻底移除查询缓存,5.7 是最后一个支持版本;因其高并发下缓存命中率低、SQL 全匹配导致冗余、不校验权限、全局锁竞争严重等缺陷,被官方认定为反模式。

MySQL 查询缓存(Query Cache)在 8.0 版本已彻底移除,5.7 是最后一个支持它的官方版本;如果你正在用 MySQL 8.0+,它根本不存在——不是“关了”,是代码里删干净了。
为什么 MySQL 会砍掉查询缓存?
它看似省事,实则副作用极重,尤其在真实业务中:
-
query_cache_type=1开启后,**任何对表的写操作(INSERT/UPDATE/DELETE/ALTER TABLE)都会清空该表所有相关缓存**,高并发更新下缓存命中率趋近于零 - 缓存 key 是原始 SQL 字符串全匹配:
SELECT * FROM user和SELECT * FROM user(末尾多一个空格)算两条不同语句,不共享缓存 - 缓存结果不校验权限变更——用户 A 查过的数据,用户 B 可能因权限不足本不该看到,却从缓存拿到了
- 全局锁竞争严重:
Qcache_hits高时,多个线程争抢缓存哈希表锁,反而拖慢读性能
怎么确认你的 MySQL 还有没有查询缓存?
执行这条命令:
SHOW VARIABLES LIKE 'query_cache%';
如果返回空结果,或只有 query_cache_type 显示为 OFF,说明它已被禁用或根本不存在(如 8.0+)。再查状态:
SHOW STATUS LIKE 'Qcache%';
若没有任何以 Qcache_ 开头的变量,就坐实了:没这玩意儿。
常见误判点:
- 看到
innodb_buffer_pool_size别误会——那是 InnoDB 缓冲池,和查询缓存无关 - 应用层用了 Redis 或 MyBatis 二级缓存,不是 MySQL 自带的查询缓存
- 某些云数据库控制台还显示“查询缓存开关”,其实是厂商自己加的代理层缓存,非原生机制
那现在靠什么替代?
真正有效的缓存策略早已下沉到更合理的位置:
-
应用层缓存:用
Redis缓存高频、低更新的查询结果(如配置表、地区列表),由业务控制过期逻辑 -
InnoDB 缓冲池(
innodb_buffer_pool_size):这才是 MySQL 当前最核心的缓存机制,缓存的是「数据页」和「索引页」,对所有读请求透明生效,且无 SQL 字符串敏感问题 - 连接层/代理缓存:如 ProxySQL 或 MySQL Router 的查询结果缓存(需手动开启),粒度可控,不与表更新强绑定
比如你常查 SELECT id,name FROM config WHERE type='mail',与其指望 MySQL 查询缓存,不如在应用启动时加载进内存,或用 Redis 存 1 小时 TTL——简单、可控、不污染数据库。
别再翻老教程配 query_cache_size 了。MySQL 官方删它,不是因为做不好,而是因为它在现代 OLTP 场景下,本身就是个反模式设计。










