人人都会AI编程

查询缓存(8.0 已移除)

更新时间:2026-07-10

查询缓存是 MySQL 早期为提高查询性能引入的一种机制,但在 MySQL 8.0 版本中已被正式移除。很多老资料里仍会提到它,所以了解它的来龙去脉对你读懂旧代码和面试都有帮助。

当时的设计初衷

查询缓存的设计逻辑很直接:如果两条 SELECT 语句的文本完全相同,并且查询的表数据没有发生变化,那么第二次执行就可以直接返回之前缓存的结果,省去解析、优化和执行的开销。它位于解析器之后,有点像一个结果集专用的缓存层。

对于读密集、写入极少的场景,比如配置表、静态字典表,这个机制确实能省下不少资源。在早期的 MySQL 版本中,这算是轻量级的性能提升手段。

为什么实际使用中很尴尬

查询缓存的理想很丰满,现实却很骨感:

  • 表写入即失效:这是最致命的。只要对查询过的表发生任何写入操作(INSERT、UPDATE、DELETE),整张表的所有查询缓存都会被清空。这意味着对于有写入活动的表,缓存几乎是刚生成就被清除,完全达不到复用的效果。绝大多数互联网业务都是读写混合的,这就让查询缓存形同虚设。
  • SQL 文本严格匹配:缓存基于文本 hash 计算,哪怕语句的大小写、空格、注释不同,都会被认为是不同的查询。SELECT FROM users WHERE id=1select from users where id=1 会被算成两条独立的缓存,极难利用。
  • 性能开销反而更大:在高并发场景下,查询缓存的加锁竞争非常严重。查询去缓存中查找需要加锁,写入时清空缓存也需要加锁,这些锁冲突经常成为系统的瓶颈点,反而拖慢了整体性能。特别是当缓存较大时,操作缓存的代价更高。
  • 对 InnoDB 不友好:InnoDB 通过 MVCC 实现一致性读,但查询缓存在返回结果之前必须检查该表的最新事务状态,以确认缓存结果是否依然可见。这个检查在 InnoDB 上开销不小,进一步侵蚀了缓存带来的收益。

从默认关闭到彻底移除

因为上述问题,从 MySQL 5.6 开始,查询缓存就已经默认禁用(query_cache_type = OFFquery_cache_size = 0)。官方多次建议不要在生产环境启用它。到了 MySQL 8.0,查询缓存的代码和相关系统变量被完全移除,相关配置项不再存在,试图设置它们会报错。

这个决定实际上得到了业界的广泛认同:一个在高并发下反而拖累系统的缓存,不如不要。

现在用什么替代

移除查询缓存并不意味着不需要缓存,而是需要把缓存放到更合适的位置,由更专业的组件来处理。现在常见的替代方案包括:

  • 应用层缓存:使用 Redis、Memcached 等外部缓存系统,将数据库的查询结果以业务对象的形式缓存起来。这种方式控制粒度更细,失效策略更灵活(可以按业务维度设置过期时间,而不是一写表就全清),并且跨实例共享。
  • Covering Index(覆盖索引):让查询所需要的列全部被索引覆盖,避免回表,直接从索引中获取结果。这是在数据库层面“以空间换时间”的经典做法。
  • Materialized View(物化视图,通过工具实现):MySQL 原生不支持物化视图,但可以通过 Flexviews 等第三方工具或定时刷新汇总表来实现,适合汇总统计类查询。

作为开发者,你只需知道:遇到旧项目或旧资料时,如果看到 query_cache 相关的配置,不必再纠结,迁移到 8.0 后这些都已不存在。在优化查询时直接考虑应用缓存或索引调优即可。