mysql 8.0 彻底删除查询缓存,因其缓存select语句字节级精确匹配的结果集,但表级失效、全局锁争用导致高并发下命中率低、性能反降;官方转向应用层缓存、innodb buffer pool优化等替代方案。

MySQL查询缓存到底缓存了什么
MySQL查询缓存(Query Cache)缓存的是 SELECT 语句的完整文本(含空格、大小写、注释)及其对应的结果集,不是执行计划,也不是表结构或索引信息。只要下一次收到一模一样的 SELECT 字符串(哪怕只是多一个空格),就可能命中缓存;但只要涉及的任意一张表发生任何 INSERT、UPDATE、DELETE 或 REPLACE,该表关联的所有缓存条目会立即失效。
它不识别语义等价:比如 SELECT * FROM user WHERE id = 1 和 SELECT id,name FROM user WHERE id = 1 即使逻辑上都只查一行,也被视为两条完全不同的查询,各自独立缓存。
为什么 MySQL 8.0 直接移除了查询缓存
根本原因是缓存失效机制带来的全局锁开销,在高并发写入场景下成了性能瓶颈。每次更新表时,MySQL 必须扫描整个查询缓存哈希表,逐个标记或删除相关条目,这个过程需要持有 LOCK_query_cache 全局互斥锁 —— 意味着所有后续查询(无论是否命中缓存)都得排队等待。
- 缓存命中率在真实业务中普遍偏低:多数应用使用参数化查询(如
SELECT * FROM order WHERE status = ?),而原始查询缓存对问号不敏感,只认字面量,导致缓存利用率极低 - InnoDB 的自适应哈希索引、缓冲池(Buffer Pool)和更成熟的客户端/中间件缓存(如 Redis、MyBatis 二级缓存)已能覆盖其价值场景
- 维护成本远高于收益:DBA 需反复调优
query_cache_size和query_cache_type,稍有不慎反而拖慢整体吞吐
升级到 MySQL 8.0 后遇到 Unknown system variable 'query_cache_size'
这是最典型的报错,说明你的配置文件或启动脚本里还留着已被移除的变量。MySQL 8.0 不再识别以下任何与查询缓存相关的配置项:
query_cache_type、query_cache_size、query_cache_limit、query_cache_min_res_unit
如果你是从 5.7 升级而来,务必检查:
-
my.cnf或my.ini中所有以query_cache_开头的行,全部删除 - 应用层代码里硬编码的
SET SESSION query_cache_type = 0这类语句,运行时会报错,需移除或用条件判断跳过 - Docker 或 Kubernetes 配置中通过环境变量注入的
MYSQL_QUERY_CACHE_SIZE类似参数,同样无效且可能引发启动失败
替代方案:现在该用什么来加速重复查询
别指望“换一个开关”就能复刻旧查询缓存的效果。真正有效的做法是分层处理:
- 高频只读小结果集(如配置表、省市区列表):交给应用层缓存,用
Redis或本地Guava Cache,可控性强、无全局锁 - 复杂报表类查询:用物化视图思路,定期写入汇总表(如
CREATE TABLE daily_sales AS SELECT ...),配合EVENT自动刷新 - ORM 场景(如 MyBatis):启用二级缓存,注意设置合理的
flushInterval和cache-ref关系,避免脏数据 - 数据库内优化:确保
WHERE条件字段有合适索引,善用EXPLAIN确认是否走了索引而不是依赖缓存“蒙混过关”
真正容易被忽略的是:很多人以为关掉查询缓存后性能会下降,实际测试常发现 QPS 反而上升 —— 因为去掉了那个隐式的全局锁热点。别急着找替代品,先压测验证你原来的缓存是否真在起作用。











