You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何未查询表的PostgreSQL匿名块会阻止Vacuum清理死行?

为什么未访问表的长匿名块会阻止VACUUM清理死行?

这本质是PostgreSQL多版本并发控制(MVCC)的快照机制导致的,核心逻辑如下:

1. MVCC的可见性规则

PostgreSQL通过事务快照控制每个事务能看到的数据版本:每个事务启动时会生成一个快照,记录当前数据库的事务状态,决定哪些数据版本对该事务可见。

只要有活跃事务的快照还能看到某个旧数据版本(死行),VACUUM就绝对不能清理这个死行——PostgreSQL必须保证任何活跃事务都能看到它启动时应该看到的数据,哪怕这个事务实际上没访问过目标表。

2. 你的场景中的关键问题

你运行的匿名块是一个持续100秒的长事务:从执行开始到循环结束,它一直处于活跃状态,持有一个创建于所有UPDATE操作之前的快照。

  • 当第二个连接执行UPDATE时,每一行都会生成新的数据版本,旧版本就成了死行,但这些旧版本在长事务的快照中是“可见”的。
  • VACUUM扫描到这些死行时,发现有活跃事务(匿名块)的快照还能看到它们,所以会判定这些死行“不可移除”。

3. 为什么没访问表也会影响?

PostgreSQL的事务快照是全局生效的,不是绑定到单个表的。只要事务处于活跃状态,它的快照就会影响所有表的VACUUM操作——VACUUM必须确保没有任何活跃事务能看到要清理的旧版本,不管这个事务有没有访问过目标表。

验证方式

你可以在匿名块运行期间执行以下查询,确认长事务的活跃状态:

SELECT pid, query, state, xact_start FROM pg_stat_activity WHERE state = 'active';

会看到匿名块对应的事务处于active状态,且xact_start时间早于你执行UPDATE的时间。

内容的提问来源于stack exchange,提问作者Saya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 14:00:07