mysql中的查询缓存与SQL执行的关系与影响

MySQL 8.0 彻底移除了查询缓存(query_cache),包括所有相关变量和逻辑,执行 SHOW VARIABLES LIKE 'query_cache%' 返回空,设置 query_cache_type 会报错;其被删除主因是高并发下全局锁争用严重、内存开销大且命中率低,现由 InnoDB 缓冲池等更优机制替代。

MySQL 查询缓存(query_cache)已彻底移除

MySQL 8.0 起,query_cache_typequery_cache_size 等所有查询缓存相关变量和逻辑已被完全删除。如果你在 8.0+ 版本中执行 SHOW VARIABLES LIKE 'query_cache%',结果为空;设置 query_cache_type=1 会报错 Unknown system variable 'query_cache_type'。这不是配置失效,而是代码级移除——它不再参与任何 SQL 执行流程。

5.7 及更早版本中,查询缓存如何干扰 SQL 执行

在启用查询缓存的旧版本中,一条 SELECT 语句的执行流程实际是:先查缓存 → 命中则跳过解析/优化/执行 → 直接返回结果。这带来几个关键副作用:

  • 缓存键基于完整的 SQL 文本(含空格、大小写、注释),SELECT * FROM tselect * from t 视为两条不同语句
  • 只要表 t 发生任何 INSERT/UPDATE/DELETE,该表关联的所有缓存条目立即失效
  • 缓存命中时,SQL_NO_CACHE 不生效;而加了 SQL_CACHE 的语句,即使结果集超大也会尝试缓存,可能拖慢整体性能
  • SELECT NOW()SELECT RAND() 这类非确定性函数,每次执行结果不同,但旧缓存机制仍会缓存第一次的结果,导致数据错误

为什么现代 MySQL 彻底放弃查询缓存

根本原因是它在高并发写入场景下成为严重瓶颈:

  • 缓存锁粒度粗:任意表更新都会触发全局缓存锁,阻塞其他查询缓存操作
  • 内存碎片与管理开销大:缓存块分配/回收依赖全局 mutex,在多核机器上反而降低吞吐
  • 收益极低:真实业务中,相同 SQL 文本重复执行比例远低于预期;而代价(锁争用、内存占用、失效风暴)却随写入量线性上升
  • 替代方案更优:InnoDB 缓冲池(innodb_buffer_pool_size)对热数据页的缓存效率更高,且无语句级一致性负担

迁移或排查时必须检查的残留痕迹

升级到 8.0 后,若应用仍带 SQL_CACHESQL_NO_CACHE 提示,MySQL 会直接忽略它们——不报错,也不生效。但以下情况需手动处理:

  • 配置文件(如 my.cnf)中残留的 query_cache_type=1 等行,启动时会被静默跳过,建议彻底删除以免误导
  • 监控脚本若还依赖 Qcache_hitsQcache_inserts 等状态变量,会查不到值,需改用 Com_select + Innodb_buffer_pool_read_requests 等指标估算有效命中
  • ORM 或中间件生成的 SQL 若硬编码了 SQL_CACHE,虽不影响运行,但属于冗余噪声,建议清理
SELECT /*+ NO_CACHE */ id FROM users WHERE status = 1;

上面这个注释在 MySQL 中无效——NO_CACHE 不是 MySQL 支持的 optimizer hint;真正能绕过缓冲池读取的是 SELECT ... FOR UPDATE 或强制磁盘读的调试手段,但日常无需干预。重点始终是调优 innodb_buffer_pool_size 和索引设计

,而不是怀念一个被删掉的功能。