mysql执行SQL时会缓存查询结果吗_mysql缓存机制解析

2次阅读

mysql 8.0 彻底移除了查询缓存(query cache),相关变量和语法均不可用;innodb buffer pool 仅缓存数据页,不缓存查询结果;所谓“sql 缓存”多源于 os page cache、客户端或代理层缓存。

mysql执行SQL时会缓存查询结果吗_mysql缓存机制解析

MySQL 默认不缓存查询结果,除非你明确启用了查询缓存(Query Cache),而该功能在 MySQL 8.0 中已被彻底移除。

MySQL 8.0 之后没有 Query Cache

从 MySQL 8.0 开始,query_cache_typequery_cache_size 等所有 Query Cache 相关变量和逻辑都被删除。执行 SHOW VARIABLES LIKE 'query_cache%' 将查不到任何结果;尝试设置 query_cache_type = 1 会报错 Unknown system variable 'query_cache_type'

  • 这是官方明确的架构决策:Query Cache 在高并发写入场景下锁竞争严重,命中率低,反而拖慢整体性能
  • 替代方案是依赖客户端缓存、应用层缓存(如 redis)、或利用 InnoDB 的 Buffer Pool 缓存数据页(但不是 SQL 结果)
  • 如果你刚升级到 8.0 并发现“缓存失效”,大概率是因为这个功能已不存在,而非配置没生效

InnoDB Buffer Pool 缓存的是数据页,不是查询结果

innodb_buffer_pool_size 控制的是内存中缓存的表数据和索引页(16KB 的 Page),不是 select 语句返回的行集。这意味着:

  • 相同 SELECT * FROM users WHERE id = 123 执行两次,第二次可能更快——但这是因为二级索引/主键页已在 Buffer Pool 中,无需磁盘 IO,不是“结果被缓存”
  • 如果执行 SELECT count(*) FROM huge_table,Buffer Pool 对它帮助极小,因为要遍历大量页,且结果集本身不落缓存
  • Buffer Pool 不理解 SQL 语义:SELECT name FROM usersSELECT email FROM users 即使走同一张表,也不会共享“结果”,只可能复用底层的数据页

哪些情况看起来像“SQL 被缓存”?

实际中常被误认为“MySQL 缓存了查询”的现象,通常来自以下原因:

  • OS page cachelinux 内核缓存了 .ibd 文件的读取页,重复查询物理文件读取变快,和 MySQL 无关
  • 客户端驱动缓存:比如 Python 的 mysql-connector-python 默认不缓存,但某些 ORM(如 SQLAlchemy 启用 Cache 插件)或自定义连接池可能做结果缓存
  • 代理层缓存:如 ProxySQL、MaxScale 配置了 query rules 做结果缓存,此时缓存发生在 MySQL 之前
  • 查询计划复用(非结果):MySQL 会缓存执行计划(EXPLAIN 输出结构),尤其对 Prepared Statement,但这不等于结果复用

想手动实现查询结果缓存,该怎么做?

MySQL 自身不提供安全可靠的查询结果缓存,必须由上层控制。常见做法:

  • 对确定性查询(无 NOW()RAND()、用户变量等),在应用中用 SQL + 参数哈希值 作为 key,存入 Redis,设置合理 TTL
  • 使用 SELECT ... INTO OUTFILE + 定时任务预热冷数据,但这属于离线缓存,不适用于实时场景
  • 避免缓存大结果集:10MB 的 SELECT * 缓存反而增加序列化/网络开销,不如让 MySQL 每次计算
  • 注意事务一致性:缓存的结果可能在其他事务提交后过期,需配合 binlog 位点或业务事件主动失效

真正容易被忽略的是:很多团队花时间调优 query_cache_size,却没意识到自己用的是 MySQL 8.0 —— 先确认版本,再谈缓存。

text=ZqhQzanResources