MySQL查询缓存一更新就全丢,因其采用整表强绑定失效机制:任一表的INSERT、UPDATE、DELETE、TRUNCATE或ALTER TABLE操作都会清空所有关联该表的缓存条目,不区分SQL复杂度或是否涉及修改字段。

MySQL查询缓存为什么一更新就全丢?
因为MySQL的查询缓存(Query Cache)不是按行、按条件失效,而是「整表强绑定」:只要对某张表执行了 INSERT、UPDATE、DELETE、TRUNCATE,甚至 ALTER TABLE,所有命中过该表的缓存条目——不管SQL多简单、多冷门——瞬间清空。
这不是bug,是设计使然。它用空间换简单性,但代价是高写入场景下命中率趋近于零。
- 哪怕只改了
user表里一条记录,SELECT name FROM user WHERE id = 123和SELECT COUNT(*) FROM user的缓存同时失效 -
ALTER TABLE user ADD COLUMN phone VARCHAR(20)会触发整个user表相关缓存批量清除,不区分是否涉及新字段 - MyISAM 和 InnoDB 在这点上行为一致——查询缓存层在存储引擎之上,不感知底层差异
MyISAM 和 InnoDB 的缓存根本不是一回事
别被“缓存”这个词骗了。MyISAM 有 key_buffer_size 缓存索引块,InnoDB 有 innodb_buffer_pool_size 缓存数据页+索引页,而 MySQL Query Cache 是独立第三层,早已在 MySQL 8.0 中被彻底移除。
也就是说:你调大 innodb_buffer_pool_size,对老版本的 Query Cache 完全没影响;反过来,关掉 Query Cache,也不会动 InnoDB 的缓冲池。
- MyISAM 的
key_buffer只存索引,不存数据;InnoDB 的buffer_pool既存聚簇索引也存二级索引,还管理脏页刷盘逻辑 - MyISAM 表锁粒度粗,缓存失效后并发读容易排队;InnoDB 行锁 + MVCC,但 Query Cache 失效时照样“一刀切”,不缓解竞争
- 如果你还在用 MySQL 5.7 或更早,并启用了 Query Cache,
SHOW VARIABLES LIKE 'query_cache%'才能确认它是否真在工作
哪些SQL注定进不了查询缓存?
不是所有合法SQL都能被缓存。MySQL在解析阶段就直接判“缓存免谈”,连进缓存队列的机会都没有。
- 含不确定函数:比如
NOW()、RAND()、CURRENT_USER()、SYSDATE()—— 缓存了也没意义,下次执行结果不同 - 访问系统表或临时表:
SELECT * FROM mysql.user或任何CREATE TEMPORARY TABLE后的查询都不缓存 - 结果超限:
query_cache_limit默认 1MB,超过此值的查询结果直接跳过缓存 - 使用子查询/UNION/视图:即使逻辑简单,如
SELECT * FROM (SELECT id FROM t LIMIT 1) AS tmp,也不进 Query Cache
现在还该用MySQL查询缓存吗?
基本不该。MySQL 8.0 已移除,5.7 官方文档明确标注为「deprecated」,且真实业务中几乎无法稳定受益。
真正有效的缓存,得下沉到应用层或中间件:比如 MyBatis 的二级缓存配合 <cache /> 和 useCache="true",或用 Redis 缓存 user:123 这样的业务键,而不是缓存 SELECT * FROM user WHERE id = 123 这种SQL字符串。
- ORM 层缓存可控制粒度:按主键缓存单行、按业务标识缓存列表ID集合、用版本号做一致性校验
- 数据库层只管把
innodb_buffer_pool_size设够(通常设为物理内存的 50%–75%),让热数据常驻内存,这才是最稳的“缓存” - 如果必须兼容老系统,至少关掉
query_cache_type=0,避免写操作频繁触发全局失效带来的性能抖动
查缓存失效原因,多数时候是在查“为什么缓存根本没生效”,而不是“为什么它后来丢了”——起点就错了。


















