postgresql/Vacuum 中的大量 live/dead 元组无法正常工作

High number of live/dead tuples in postgresql/ Vacuum not working

有一个 table,它有 200 行。但是显示的活元组数量不止于此(大约 60K)。

select count(*) from subscriber_offset_manager;
 count 
-------
   200
(1 row)


 SELECT schemaname,relname,n_live_tup,n_dead_tup FROM pg_stat_user_tables  where relname='subscriber_offset_manager' ORDER BY n_dead_tup
;
 schemaname |          relname          | n_live_tup | n_dead_tup 
------------+---------------------------+------------+------------
 public     | subscriber_offset_manager |      61453 |          5
(1 row)

但是从 pg_stat_activity 和 pg_locks 可以看出,我们无法跟踪任何打开的连接。

SELECT query, state,locktype,mode
FROM pg_locks
JOIN pg_stat_activity
  USING (pid)
WHERE relation::regclass = 'subscriber_offset_manager'::regclass
  ;
 query | state | locktype | mode 
-------+-------+----------+------
(0 rows)

我也在这个 table 上尝试了全真空,结果如下:

这是输出。

vacuum FULL VERBOSE ANALYZE subscriber_offset_manager;
INFO:  vacuuming "public.subscriber_offset_manager"
INFO:  "subscriber_offset_manager": found 0 removable, 67920 nonremovable row versions in 714 pages
DETAIL:  67720 dead row versions cannot be removed yet.
CPU 0.01s/0.06u sec elapsed 0.13 sec.
INFO:  analyzing "public.subscriber_offset_manager"
INFO:  "subscriber_offset_manager": scanned 710 of 710 pages, containing 200 live rows and 67720 dead rows; 200 rows in sample, 200 estimated total rows
VACUUM

 SELECT schemaname,relname,n_live_tup,n_dead_tup FROM pg_stat_user_tables  where relname='subscriber_offset_manager' ORDER BY n_dead_tup
;
 schemaname |          relname          | n_live_tup | n_dead_tup 
------------+---------------------------+------------+------------
 public     | subscriber_offset_manager |        200 |      67749

10 秒后

SELECT schemaname,relname,n_live_tup,n_dead_tup FROM pg_stat_user_tables  where relname='subscriber_offset_manager' ORDER BY n_dead_tup
;
 schemaname |          relname          | n_live_tup | n_dead_tup 
------------+---------------------------+------------+------------
 public     | subscriber_offset_manager |      68325 |        132

我们的应用如何查询此 table .

另一个有趣的观察: - 当我停止我的 java 应用程序然后进行完全真空处理时,它工作正常(行数和活动元组数变得相等)。因此,如果我们 select 并从 java app 不断更新,就会出现问题。 –

Problem/Issue

这些活元组有时会变成死元组,有时又会活过来。

由于 table 的上述行为 select 需要时间并增加服务器上的负载,因为那里有很多 live/deadtuples ..

毕竟可能会有锁,您的查询可能会产生误导:

SELECT query, state,locktype,mode
FROM pg_locks
JOIN pg_stat_activity USING (pid)
WHERE relation = 'subscriber_offset_manager'::regclass

pg_locks.pid 可以为 NULL,则连接将消除行。 The manual for Postgres 9.3:

Process ID of the server process holding or awaiting this lock, or null if the lock is held by a prepared transaction

大胆强调我的。 (在第 10 页中仍然相同。)

您对简单查询有什么了解吗?

SELECT * FROM pg_locks
WHERE relation = 'subscriber_offset_manager'::regclass;

这可以解释为什么 VACUUM 抱怨:

DETAIL:  67720 dead row versions cannot be removed yet.

反过来,这会指出您的应用程序逻辑/查询中存在问题,锁定了不必要的行数。

我的第一个想法是 long 运行 transactions,其中即使是简单的 SELECT(获取低级 ACCESS SHARE 锁)也可以阻塞VACUUM 从完成它的工作。 20 个并行线程可能会无限期地链接起来并锁定 VACUUM。使您的交易(及其锁定)尽可能简短。并确保您的查询得到优化,并且不要锁定不必要的行。

还有一点需要注意:transaction isolationSERIALIZABLEREPEATABLE READ 使 VACUUM 更难清理。默认 READ COMMITTED 模式的限制较少,但 VACUUM 仍然可以像讨论的那样被阻止。

相关:

我知道阻碍 VACUUM 工作的三件事:

  • 长运行笔交易。

  • 未提交的准备事务。

  • 过时的复制槽。

详情见my blog post

我找到问题了☺。

为了理解这个问题,请考虑以下流程:

线程 1 -

  • 打开休眠会话
  • Table-A 进行一些查询
  • Select 来自 subscriber_offset_manager
  • 更新subscriber_offset_manager
  • 关闭会话。

Thread-1运行类型的许多线程并行。

线程 2 -

  • 这些类型的线程 运行 是并行的。
  • 打开休眠会话
  • Table-A
  • 上进行一些 select 查询
  • 不关闭会话。(会话泄漏。)

临时解决方案 - 如果我使用 pg_cancel_backend 关闭所有由 Thread-2 建立的连接,则吸尘开始工作。

此外,我们已多次重现该问题,并尝试了此解决方案并且有效。

现在有以下疑惑还没有解答。

  1. 为什么 postgres 没有显示与 table "subscriber_offset_manager" 相关的任何数据。
  2. 如果我们 运行 select 在 Table-A ,使用 psql 。
  3. 为什么 postgres 与 jdbc 这样工作。

一些更令人兴奋的观察:

  1. 事件如果我们运行在不同的会话中查询“subscriber_offset_manager”然后也会发出问题;
  2. 我们在这里发现许多实例,其中线程 2 正在处理第三个 table“Table-C”,问题即将出现
  3. pg_stat_activity 中所有这些类型的 od 交易状态是“idle_in_transaction。”

@Erwin Brandstetter 和@Laurenz Albe,如果您知道存在与 postgres/jdbc 相关的错误。