MySQL 缓存机制与查询缓存的消亡史
文章目录
- MySQL 缓存机制与查询缓存的消亡史
- 一、前言
- 二、Query Cache 机制是怎样工作的?
- 示例:
- 三、查询缓存为什么失败?(核心三大原因)
- 1. **表只要发生任何写入,所有缓存全部被清空**
- 2. **Query Cache 使用全局锁,存在严重的锁竞争**
- 3. SQL 必须“字节级一致”才能命中缓存(极端苛刻)
- 四、MySQL 8.0 为什么彻底移除 Query Cache?
- 五、现代系统如何替代 Query Cache?
- 1. InnoDB Buffer Pool(真正的 MySQL 核心缓存)
- 2. Redis(现代互联网缓存方案首选)
- 3. 本地缓存(Caffeine/Guava)
- 六、面试高频问题(标准一段式回答)
- 七、总结
MySQL 缓存机制与查询缓存的消亡史
一、前言
大家好,我是程序员卷卷狗。
MySQL 在 5.x 时代提供了一种名为 Query Cache(查询缓存) 的机制,
很多人以为它能提升查询性能,但在高并发环境中它反而导致 性能下降。
最终 MySQL 在 8.0 中彻底移除了查询缓存。
查询缓存失败的核心原因有三点:
- 一旦表有写入,所有相关缓存全部失效(高并发写场景完全不可用)
- 存在全局锁,反而拖慢性能
- 缓存粒度太粗,命中条件极其苛刻
现代系统完全转向使用 Redis / Caffeine / InnoDB Buffer Pool 作为缓存体系。
一句话概括本篇内容:
Query Cache 是理想主义设计,不适合互联网高并发场景,因此被 MySQL 官方永久删除。
二、Query Cache 机制是怎样工作的?
查询缓存的工作流程如下:
SQL 文本作为 key
查询结果作为 value
存入内存查询缓存
当客户端再次执行相同 SQL:
→ MySQL 比较 SQL 字节级文本
→ 若完全一致,则直接返回缓存结果
示例:
SELECT * FROM user WHERE age > 20;
如果相同的 SQL 再执行一次,只要数据没有变化,
MySQL 会直接返回缓存,而不需要重新查询。
看似完美对不对?
但问题马上出现了——
三、查询缓存为什么失败?(核心三大原因)
下面这部分是面试必问、真实项目必踩的一节。
1. 表只要发生任何写入,所有缓存全部被清空
UPDATE user SET age=25 WHERE id=1;
这条 SQL 会导致:
- user 表所有相关缓存直接清空
- 缓存重建成本极高
- 高频写入场景根本无法使用
互联网系统都是 读写混合 + 高并发写入,
因此 Query Cache 几乎永远处于“没命中 → 被清空 → 重建 → 再被清空”的状态。
官方原话:
“在写多系统中,Query Cache hit rate 会非常低。”
2. Query Cache 使用全局锁,存在严重的锁竞争
查询缓存的增删需要使用 全局锁(global mutex)。
这意味着:
- 写入线程会阻塞所有读线程
- 多线程争用锁,导致 CPU 飙高
- 在高并发场景中性能反而更慢
你没看错——
开启查询缓存会让系统更慢。
3. SQL 必须“字节级一致”才能命中缓存(极端苛刻)
Query Cache 匹配规则:
SQL 文本 + 大小写 + 空格 + 注释 → 完全一致才能命中
例如:
SELECT * FROM user WHERE id=1;
与:
select * from user where id = 1;
无法命中同一个缓存。
这在实际项目中几乎不可控。
ORM(MyBatis/JPA/Hibernate)轻轻动一下“空格”都会让缓存失效。
四、MySQL 8.0 为什么彻底移除 Query Cache?
官方在 8.0 Release Notes 中明确宣布:
已完全移除 Query Cache 功能。
原因:Query Cache 导致性能下降,不适用于现代写密集型业务。
其核心原因:
- 写多 → 缓存全清空
- 全局锁 → 线程阻塞
- 粒度粗 → 命中率极低
- 添加复杂度 → 与优化器/执行器冲突
- 不适合云原生、分布式、高并发场景
一句话:
Query Cache = 烧钱不出力,甚至拖后腿
五、现代系统如何替代 Query Cache?
MySQL 的“缓存接力棒”交给了三个现代方案。
1. InnoDB Buffer Pool(真正的 MySQL 核心缓存)
缓存内容包括:
- 热数据页(data page)
- 索引页(index page)
- undo 页
- 自适应哈希索引
Buffer Pool 是 MySQL 最重要的性能来源,
几乎所有查询都会优先从内存页读取。
Query Cache 不行,但 Buffer Pool 永生。
2. Redis(现代互联网缓存方案首选)
替代 Query Cache 的首要方案。
架构:
读:
先查 Redis → MISS → 查 MySQL → 写回 Redis写:
更新 MySQL → 删除 Redis 缓存(缓存失效方案)
优点:
- 吞吐量极高(10w+ QPS)
- 内存级访问
- 键值粒度的缓存控制
- 分布式可扩容
- 主从复制/Cluster 天生支持高可用
这就是为什么 Redis 彻底取代 Query Cache。
3. 本地缓存(Caffeine/Guava)
适用于:
- 高频查询
- 配置/小字典
- 热点数据
性能:纳秒级访问。
六、面试高频问题(标准一段式回答)
面试官:MySQL 查询缓存为什么被移除?
你:
MySQL 的 Query Cache 是一种结果缓存,但它与现代互联网写多读少的业务模式完全不兼容。因为只要表发生写入,所有相关缓存都会失效,而且查询缓存采用全局锁,导致高并发场景下反而降低性能。此外 SQL 文本必须字节级完全一致才能命中缓存,命中率非常低。最终 MySQL 在 8.0 中彻底移除 Query Cache,并建议使用 InnoDB Buffer Pool、Redis、或本地缓存来替代。
七、总结
Query Cache 曾经被寄予厚望,但最终完全失败。
由此带给我们的启示:
- 缓存必须细粒度,而不是粗暴缓存整个查询结果
- 高并发写入场景必须避免全局锁
- 缓存必须能水平扩容
- 真正的 MySQL 缓存是 Buffer Pool,而不是 Query Cache
最终:
Query Cache 已死,Redis 当立,Buffer Pool 永生。
