MySQL 8.0+已彻底移除查询缓存,无法启用;仅5.7及更早版本支持,需先执行SHOW VARIABLES LIKE 'have_query_cache'和SELECT VERSION()确认版本与功能可用性,再在my.cnf的[mysqld]段配置query_cache_type、query_cache_size等参数并重启生效。

MySQL 8.0 及以上版本已彻底移除查询缓存(query_cache),安装后无法开启;只有 MySQL 5.7 及更早版本才支持该功能。如果你刚装完 MySQL,第一步不是配缓存,而是先确认版本和是否支持。
怎么判断你的 MySQL 支持 query_cache
直接执行:SHOW VARIABLES LIKE 'have_query_cache';
如果返回 have_query_cache 值为 YES,说明编译时启用了该功能;若为 NO 或查无结果(MySQL 8.0+),就不用往下看了——硬配 query_cache_type 也不会生效。
顺手再查版本:SELECT VERSION();
输出如 5.7.40 可继续;8.0.33 或更高,跳过本方案,改用应用层缓存或 Redis。
my.cnf 里怎么写 query_cache 参数
仅适用于支持版本。在 [mysqld] 段添加以下三行(缺一不可):
-
query_cache_type = 1:启用自动缓存(SELECT默认进缓存,除非显式加SQL_NO_CACHE) -
query_cache_size = 64M:分配 64MB 内存,设为0或非 1024 整数倍会导致实际分配异常 -
query_cache_limit = 2M:单条查询结果超 2MB 不缓存,避免大结果挤占空间
可选但推荐加:query_cache_min_res_unit = 4k:减少内存碎片,尤其当大量小查询共存时有效。
改完必须重启 MySQL:sudo systemctl restart mysql(Linux)或服务管理器重启(Windows)。
为什么 SHOW STATUS 显示 Qcache_hits 一直为 0
常见原因不是配置没生效,而是查询本身不满足缓存条件:
- SQL 语句含非确定性函数:如
NOW()、RAND()、USER()、CONNECTION_ID()—— 这些会让 MySQL 直接跳过缓存 - 查询涉及临时表、用户变量(
@var)、存储函数、LOCK IN SHARE MODE等 - 表被修改过:只要执行过
INSERT/UPDATE/DELETE,该表所有相关缓存立即失效 - 大小写或空格差异:
SELECT * FROM t和select * from t被视为不同查询,无法命中
验证是否真缓存了,用完全一致的纯字面量查询测试:SELECT 1; 执行两次,看 Qcache_hits 是否 +1。
query_cache_size 设多大才合适
不是越大越好。缓存管理本身有开销,尤其在高并发写入场景下,Qcache_lowmem_prunes 频繁升高说明缓存反复被清空,反而拖慢性能。
观察关键指标:SHOW STATUS LIKE 'Qcache%';
-
Qcache_hits / (Qcache_hits + Qcache_inserts)是命中率,低于 0.2(20%)说明收益很低 -
Qcache_lowmem_prunes持续增长,且远高于Qcache_inserts,说明内存太小或缓存碎片严重 -
Qcache_free_memory长期接近 0,但Qcache_queries_in_cache很低,大概率是query_cache_min_res_unit设得过大,导致小查询无法分配块
调优节奏:从 16M 起步,上线后观察 24 小时,再根据 Qcache_lowmem_prunes 和命中率微调。超过 256M 通常得不偿失。
真正容易被忽略的是:即使参数全对、查询也符合条件,只要数据库里有任何一张表被频繁更新,整个查询缓存就会变成“高损耗低收益”的摆设——它本质只适合读远多于写的静态数据场景,比如配置表、地区字典这类几乎不变的表。


















