大事务本身不直接加载冷数据页,但会阻塞purge线程清理oldest_modification,导致flush_list中脏页滞留、占比攀升,间接加剧缓存污染;真正加载大量冷数据页的是其触发的全表扫描或大范围索引扫描操作。

大事务会把冷数据页大量加载进Buffer Pool
执行一个扫描全表或跨多索引的大事务(比如 UPDATE t1 SET status=1 WHERE create_time ),InnoDB 会按需把涉及的每一个数据页从磁盘读入 Buffer Pool。这些页原本可能长期未被访问(冷数据),但一旦被大事务“顺手”加载进来,就会挤占原本属于热点数据页的内存空间。
Buffer Pool 使用 LRU 链表管理页的生命周期,但 InnoDB 的 LRU 实现是分段的:新加载的页先进入“young sublist”,只有被再次访问才会晋升到“old sublist”。而大事务中的页通常只被顺序扫描一次,不会二次访问,所以它们卡在 young sublist 尾部,既不热也不被淘汰——形成“伪热点”,实际却毫无复用价值。
- 这类页占用大量内存,却几乎不再被后续查询命中
- 真实高频访问的热页被迫被挤出,导致后续查询频繁触发
Innodb_buffer_pool_reads - 现象上表现为缓存命中率骤降,
Innodb_buffer_pool_read_requests增速远高于Innodb_buffer_pool_reads的下降速度
大事务产生的脏页集中刷盘会干扰后台刷新节奏
大事务修改大量数据后,会产生海量 dirty page。InnoDB 的后台线程(如 page cleaner)需要把这些脏页刷回磁盘,但刷盘不是均匀进行的——它依赖 innodb_max_dirty_pages_pct 和 innodb_io_capacity 等参数做节流。当脏页比例突然飙升,后台线程会被迫加速刷盘,可能引发以下连锁反应:
- 磁盘 I/O 突增,影响其他查询的响应延迟
- 为腾出空闲页(
free page)给新请求,Buffer Pool 被迫提前淘汰部分 clean page,进一步降低缓存有效性 - 如果此时恰好触发 checkpoint,还会阻塞 DML 操作,放大业务抖动
Change Buffer 合并被大事务强制触发
非唯一二级索引的更新默认走 change buffer,避免随机 IO。但只要某页被大事务读入 Buffer Pool(比如通过主键查到了对应行),InnoDB 就必须立刻把该页上积压的所有 change buffer 记录合并进去——这个过程叫 “purge on read”。
大事务常伴随范围扫描,很容易把大量本该“懒合并”的二级索引页拉进内存,导致:
- 额外的 CPU 开销用于合并操作
- 更多内存被临时占用(合并后的页体积变大)
- 原本可延迟的磁盘写入被提前激发,加剧 I/O 压力
真正难处理的是“不可见污染”
Buffer Pool 污染最麻烦的地方不在内存用量本身,而在于它难以被监控和归因。你不会看到报错,也不会触发告警;只会发现某天开始 SELECT 变慢、SHOW ENGINE INNODB STATUS 里 Buffer pool hit rate 掉到 95% 以下、Pages made young 异常升高——但具体哪条 SQL 干的、污染了哪些页,没有直接视图能定位。这时候只能靠 INFORMATION_SCHEMA.INNODB_BUFFER_PAGE(需开启 innodb_buffer_page 监控)配合事务时间窗口反推,实操成本高,且生产环境往往不敢开。











