从 JDBC 发出时 Postgres 真空/恶魔部分工作

问题描述

首先,我知道依靠应用程序层的手动清理很奇怪,但这就是我们决定运行它的方式。 我有以下堆栈:

  1. HikariCP
  2. JDBC
  3. AWS 中的 Postgres 11

现在问题来了。当我们重新开始使用 autovacuum=off 的全新桌子时,手动真空工作正常。我可以看到 dead_tuples 的数量增长到阈值然后回到 0。表在并行连接中被大量更新(也正在使用 HOT)。在某些时候,死行的数量就像 100k 跳到阈值并回到 100k。 n_dead_tuples 缓慢上升。

现在最糟糕的是,当您从 pg 控制台发出真空时,所有死元组都被清除,但奇怪的是,当应用程序发出真空时,它成功了,但部分清除了“阈值数量”记录”,但不是全部? 现在我很确定以下几点:

  • 分析未运行,也未自动清空
  • 没有长时间运行的事务
  • 没有进行复制
  • 这些表是“私有的”

从控制台发出真空与 JDBC 上的自动提交有什么区别?为什么从控制台发出的真空正在清理 ALL 元组,而来自 JDBC 的真空只清理部分? JDBC 真空在池中的新连接中运行,具有认隔离级别,是的,更新并行进行,但这与从控制台执行真空时相同。

池中的连接是否以某种方式损坏并且看不到更新?是隔离问题吗? 能见度图损坏? 索引引用旧元组

旁注:我观察到了相同的行为,自动真空开启和成本限制通过屋顶,如 4000-8000 ,认阈值 + 5% 。起初,n_dead_tuples 接近 0 大约 4-5 个小时......第二天,表是 86gigs,有数百万个死元组。所有其他桌子都被吸尘了,还可以...

PS:我将尝试在 JDBC 中记录 vac 详细信息。 PS2:因为我们在 AWS 中运行,所以它可能是导致它停止清理的备份吗?

ps3:当提到真空时,我指的是简单真空,而不是完全真空。我们不会发布完全真空。

解决方法

主要问题是真空是由另一个用户运行的。我看到的清空是热更新 + 选择运行在该数据上,导致页面即时清空。

下一步:清空会受到跨所有架构和表的长时间运行的事务的影响。是的,所有模式和表。更改为正确的用户修复了真空,但如果任何其他 schema.table 中存在 open_in_transaction,它将被忽略。

工作维护记忆有帮助,但最终当系统处于高负载时,所有吸尘都会暂停。

所以我们稍微升级了数据库的资源,并添加了一个监视器,以便在出现任何问题时帮助我们。