MySQL 5.7 中 query_cache_type 和 query_cache_size 怎么设才生效
MySQL 5.7 默认已禁用查询缓存(
query_cache_type=0),即使你把
query_cache_size设成 256M,缓存也不会工作。必须同时满足两个条件:一是
query_cache_type设为
1(ON),二是
query_cache_size>
1048576(即至少 1MB)——小于这个值会被 MySQL 自动置为 0。
常见错误是只改了
query_cache_size却忘了开
query_cache_type,或者在配置文件里写成了
query_cache_size = 256(单位是字节,实际只配了 256 字节)。
query_cache_type=1:按需缓存(SELECT 不加
SQL_NO_CACHE才考虑缓存)
query_cache_type=2:只缓存带
SQL_CACHE提示的语句,更可控但需改代码
query_cache_size必须是 1024 的倍数,否则启动时被截断 修改后必须重启 MySQL(不是
SET GLOBAL就能热生效)
什么样的 SELECT 语句根本不会进查询缓存
不是所有 SELECT 都能被缓存。只要语句里出现以下任一情况,MySQL 会直接跳过缓存逻辑:
含用户变量:SELECT @x := 1调用非确定性函数:
NOW()、
UUID()、
RAND()、
USER()访问系统表:
information_schema或
performance_schema表名带数据库前缀但当前库不匹配:
SELECT * FROM test.t1而当前
USE的是
otherdb使用
LOCK IN SHARE MODE或
FOR UPDATE结果集超过
query_cache_limit(默认 1MB)
尤其注意:哪怕只是
SELECT COUNT(*) FROM t WHERE created_at > NOW() - INTERVAL 1 DAY,因为有
NOW(),每次执行都会绕过缓存,形同虚设。
开启查询缓存反而变慢?关键瓶颈在哪
查询缓存不是“开就快”,它在高并发写入场景下会成为性能杀手。核心问题在于:任何对表的写操作(
INSERT、
UPDATE、
DELETE、
TRUNCATE)都会导致该表所有缓存条目被立即失效,并触发全局锁(
QUERY CACHE LOCK)。
这意味着:一张被频繁更新的热点表(比如订单表),它的缓存命中率极低,但每次写操作却要花时间清理缓存 + 拿锁,反而拖慢整体吞吐。
可通过以下方式验证是否被反噬:
SHOW STATUS LIKE 'Qcache%';
重点关注三个指标:
Qcache_hits / (Qcache_hits + Com_select)
Qcache_lowmem_prunes > 0→ 内存不够,频繁淘汰旧缓存
Qcache_inserts接近
Com_select→ 几乎每条 SELECT 都尝试缓存,但很快被清掉
MySQL 8.0+ 完全移除了查询缓存,替代方案是什么
MySQL 8.0 直接删掉了整个查询缓存模块(
query_cache_type等参数已废弃),官方明确表示:在大多数真实负载下,它带来的锁竞争和维护开销远大于收益。
如果你正从 5.7 升级到 8.0,别试图找“等效替代参数”——没有。应转向更现代的优化路径:
用应用层缓存(Redis / Memcached)控制缓存粒度和失效逻辑 善用索引覆盖、延迟关联、物化视图(通过汇总表)减少重复计算 对固定参数的报表类查询,用CREATE TABLE ... AS SELECT预生成快照 启用
innodb_buffer_pool_size(通常设为物理内存 70~80%)提升数据页缓存效率,这比查询缓存更底层、更稳定
真正容易被忽略的是:很多人升级后还在监控
Qcache_hits,殊不知这个状态变量在 8.0 里压根不存在了——检查前先确认版本和参数是否已被弃用。
