导读:本期聚焦于小伙伴创作的《MySQL 真的会缓存查询结果吗?深入解析查询缓存机制》,敬请观看详情。把一条复杂 SQL 反复执行,响应时间却没明显变快,多半是误解了 MySQL 的查询缓存。该机制只会把 SELECT 语句和其返回结果以哈希表形式缓存,任意涉及表的数据或结构变动都会让相关缓存失效。自 MySQL 5.7 后官方已标记废弃,8.0 直接移除,因为在高并发写场景下维护缓存锁开销大,命中率极低。实际调优应关注索引设计、执行计划与缓冲池,而非依赖查询缓存。

MySQL 是否缓存查询结果是许多刚接触数据库性能调优的人会产生的疑问。从早期版本的设计来看,MySQL 确实提供过一种名为查询缓存(Query Cache)的内置机制,但它和我们日常理解的通用结果缓存并不完全相同,而且在高版本中已经被官方移除。理解它的工作原理与局限,有助于避免在架构设计上踩坑。

MySQL 真的会缓存查询结果吗?深入解析查询缓存机制

一、MySQL 查询缓存是什么

查询缓存是 MySQL 服务端在内存中维护的一块区域,用来存储客户端发送的 SELECT 语句文本以及对应的完整结果集。当新的查询到达时,MySQL 会先计算该 SQL 语句的哈希值,若能在缓存中找到完全相同的语句(包括空格、大小写、数据库名等都必须一致),就直接返回缓存结果,跳过解析、优化和执行阶段。

这种机制听起来能显著提升性能,但实际上约束非常严格。只要被查询的表中发生了任何数据修改(INSERT、UPDATE、DELETE、TRUNCATE 等)或者表结构变更(ALTER TABLE),所有涉及该表的缓存条目都会立即失效并被清除。因此在写操作频繁的系统中,查询缓存的命中率往往低得可怜,反而因为频繁的失效检查和锁竞争拖慢整体吞吐。

二、查询缓存的配置与验证

在 MySQL 5.6 及之前的版本中,可以通过系统变量来开启和调节查询缓存。核心参数包括 query_cache_type 和 query_cache_size。下面的示例展示了如何查看当前配置以及手动启用缓存:

-- 查看查询缓存相关配置
SHOW VARIABLES LIKE 'query_cache%';

-- 临时开启查询缓存(仅对当前会话生效需设为 DEMAND)
SET GLOBAL query_cache_type = ON;
SET GLOBAL query_cache_size = 67108864; -- 分配 64MB 缓存

-- 执行一条会被缓存的查询
SELECT SQL_CACHE * FROM user WHERE id = 1;

-- 查看缓存命中情况
SHOW STATUS LIKE 'Qcache%';

通过 Qcache_hits 和 Qcache_inserts 的比值,可以粗略判断缓存是否有效。如果 Qcache_not_cached 数值很大,说明大量查询因为不符合缓存条件(例如使用了用户变量、临时表、不确定函数如 NOW())而被直接跳过。

需要注意的是,SQL_CACHE 和 SQL_NO_CACHE 提示符只有在 query_cache_type 设为 DEMAND 时才具有强制意义。当类型设为 ON 时,所有可缓存查询都会默认缓存,除非显式写上 SQL_NO_CACHE。这种细粒度控制在实际业务中很少被正确使用,多数团队索性关闭该功能。

三、为什么官方放弃了查询缓存

从 MySQL 5.7 开始,官方文档已将查询缓存标记为废弃(deprecated),到 MySQL 8.0 则彻底删除该特性。根本原因在于它的设计无法适应现代高并发场景。查询缓存使用单一互斥锁保护整个缓存区,在多核服务器上,大量线程争用同一把锁会成为严重瓶颈。

此外,缓存失效的粒度太粗。任何一条针对某表的写入都会令该表所有查询缓存失效,这意味着即便只是更新一行数据,相关表上成千上万条不同条件的 SELECT 缓存都会瞬间清空。在读写混合的业务里,缓存几乎刚写入就被淘汰,资源投入产出比极低。官方也建议用户改用应用层缓存(如 Redis)或重点优化 InnoDB 缓冲池。

版本查询缓存状态建议
MySQL 5.6 及以前默认开启可选写少读多且 SQL 固定时可谨慎启用
MySQL 5.7废弃逐步关闭,避免依赖
MySQL 8.0+已移除使用 Redis 或优化索引与缓冲池

四、替代方案与正确优化思路

如果业务确实需要缓存查询结果,更合理的做法是在应用端引入分布式缓存组件。例如使用 Redis 以查询特征(如方法名加参数哈希)作为 key 存储序列化结果,并借助消息队列在写操作时精准淘汰对应 key,这样失效粒度可以控制到具体业务对象。

对于数据库自身,应当把精力放在 InnoDB 的 buffer pool 上。buffer pool 缓存的是数据页和索引页,不属于 SQL 结果缓存,但能大幅减少磁盘 IO。配合合理的复合索引、覆盖索引以及避免 SELECT * 的写法,往往比查询缓存带来更稳定的性能提升。下方代码展示了如何通过 EXPLAIN 检查语句是否命中索引:

-- 分析查询执行计划
EXPLAIN SELECT id, name FROM user WHERE status = 1 AND create_time > '2023-01-01';

-- 若 type 为 ALL 表示全表扫描,需考虑建立索引
-- 建立联合索引示例
CREATE INDEX idx_status_ctime ON user(status, create_time);

在绝大多数生产环境中,关闭 MySQL 查询缓存不仅不会降低性能,反而能减少锁等待和内存碎片。理解这一点,我们就能更清醒地看待数据库层的缓存能力边界,把架构设计建立在可扩展、可观测的基础之上。

五、常见误区总结

不少人以为只要数据库开着查询缓存,重复页面请求背后的相同 SQL 就一定会变快,这是典型误解。因为缓存要求 SQL 文本字节级一致,而很多 ORM 框架会自动拼接空格、注释或排序参数,导致哈希不匹配。再加上写操作清缓存的特性,实际命中率可能趋近于零。

另一个误区是认为查询缓存能替代 Redis。二者层级不同:查询缓存位于数据库内部、随实例重启消失且受限单机内存;Redis 等外部缓存可跨服务共享、支持复杂淘汰策略与集群扩展。明确职责分工,才能让系统既稳健又高效。

MySQL查询缓存query_cache修改时间:2026-08-07 09:15:28

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。