mysql 8.0 彻底删除查询缓存模块,因其全局锁导致高并发排队、表级失效使命中率趋近于零、sql字节级匹配严苛、内存管理低效且与innodb缓冲池冲突。

UPDATE语句不走查询缓存,但会清空对应表的全部缓存
MySQL 8.0 已彻底移除查询缓存模块,但即使在 5.7 等旧版本中,UPDATE 也从不读取缓存——它只触发清空。只要执行了 UPDATE users SET name = 'a' WHERE id = 1,整个 users 表相关的所有 SELECT 缓存条目都会被立即失效。
这导致高更新频率下缓存命中率趋近于零,反而增加维护开销。所以别指望靠查询缓存加速写多读少场景;更现实的做法是:关掉它(query_cache_type = 0),或直接升级到 8.0+ 避免配置干扰。
InnoDB 加锁行为完全由 WHERE 条件是否命中索引 + 隔离级别共同决定
不是“有 WHERE 就安全”,也不是“没索引就一定锁全表”。真实加锁粒度取决于执行计划是否能走索引、以及当前事务隔离级别:
-
WHERE id = 1(主键等值)→ 只加行锁(Record Lock) -
WHERE age > 25(范围查询,RR 隔离)→ 加临键锁(Next-Key Lock),覆盖匹配行 + 后续间隙 -
WHERE name LIKE '%abc'(无法使用索引)→ 全聚簇索引扫描,对所有扫描行加临键锁,极易阻塞插入 - 显式事务中未
COMMIT→ 锁持续持有,可能引发Lock wait timeout exceeded
redo log 和 binlog 的两阶段提交(2PC)保障 crash safe
MySQL 必须确保 redo log 和 binlog 一致,否则主从同步或崩溃恢复会出错。实际流程是:
- 事务 prepare 阶段:写入
redo log(状态为 PREPARE),不刷盘 - 事务 write binlog 阶段:写入
binlog文件,并刷盘(sync_binlog = 1时) - 事务 commit 阶段:写入
redo log的 COMMIT 标记,并刷盘
如果 crash 发生在 prepare 之后、binlog 写入之前,重启后该事务会被回滚;如果发生在 binlog 写入之后、commit 之前,重启后会通过 binlog 补偿提交。这个机制依赖 innodb_support_xa = ON(8.0.26+ 默认启用)。
Buffer Pool 中修改数据后,脏页何时刷回磁盘不可控
执行 UPDATE 后,InnoDB 只改内存中的 data page,变成脏页。刷盘时机由后台线程异步控制,不受 SQL 语句本身影响:
- 脏页比例超过
innodb_max_dirty_pages_pct(默认 75%)→ 启动渐进式刷新 - Redo log 空间将满(
sharp checkpoint)→ 强制刷一批关联脏页,可能引发 IO 尖峰 - 正常关闭 MySQL 时 → 会同步刷完所有脏页
这意味着你执行完 UPDATE 并 COMMIT,数据在物理磁盘上可能还没落盘——只要 redo log 完整,崩溃后就能恢复。别误以为 COMMIT = 磁盘写完,这是最常见的认知偏差。











