postgresql / Vacuum中大量的活动/死元组不起作用

时间:2018-08-14 15:09:49

标签: java postgresql performance hibernate postgresql-9.3

有一个表,其中有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)

我也在这张桌子上尝试了全真空,结果如下:

  • 一直没有删除任何行
  • 有时所有的活元组变成死元组。

这里输出。

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

我们的应用程序如何查询此表。

  • 我们的应用程序通常选择一些行,并根据一些业务计算来更新该行。

    选择查询-根据某些ID进行选择

    从subscriber_offset_manager中选择*,其中shard_id = 1;

    更新查询-为此选定的分片ID更新其他一些列

  • 大约20个线程并行执行此操作,而一个线程仅在一行上工作。

  • app是用Java编写的,我们正在使用hibernate进行db操作。
  • PostgreSQL版本是9.3.24

另一个有趣的发现:  -当我停止我的Java应用程序,然后完全吸尘时,它工作正常(行数和活动元组变为相等)。因此,如果我们从Java应用程序中连续选择并更新,则会出问题。 –

问题/问题

这些活的元组有时会变成死的元组,过一段时间后又会复活。

由于上述行为,请从表中进行选择,这会花费一些时间并增加服务器的负载,因为那里有很多实时/重复数据..

3 个答案:

答案 0 :(得分:4)

我遇到了问题。

要了解该问题,请考虑以下流程:

线程1-

  • 打开休眠会话
  • 表A
  • 进行一些查询
  • subscriber_offset_manager
  • 中选择
  • 更新 subscriber_offset_manager
  • 关闭会话。

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

线程2-

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

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

我们还多次创建了该问题,并尝试了此解决方案,并且该解决方案有效。

现在,有以下疑问仍未得到解答。

  1. 为什么postgres没有显示与表“ subscriber_offset_manager ”相关的任何数据。
  2. 如果我们使用psql在 Table-A 上运行select,而不是运行 Thread-2 时,不会重新创建此问题。
  3. 为什么postgres可以与jdbc一起使用。

更多令人震惊的观察结果:

  1. 事件,如果我们在不同的会话中对“ subscriber_offset_manager ”运行查询,那么还会发出问题;
  2. 我们在这里发现许多实例,其中线程2正在处理某些第三张表​​“ Table-C ”,并且问题即将到来
  3. pg_stat_activity中所有这些类型的od交易状态为“ idle_in_transaction ”。

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

答案 1 :(得分:3)

我知道阻止VACUUM正常工作的三件事:

  • 长期交易。

  • 未完成的准备好的交易。

  • 陈旧的复制插槽。

有关详细信息,请参见my blog post

答案 2 :(得分:2)

毕竟可能有锁,您的查询可能会引起误解:

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:

  

持有或正在等待此锁的服务器进程的进程ID,;如果锁是由准备好的事务持有的,则为null

我强调大胆。 (第10页还是一样)。

您能从简单查询中得到任何东西吗?

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

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

DETAIL:  67720 dead row versions cannot be removed yet.

反过来,这将指向您的应用程序逻辑/查询中的问题,从而锁定了不必要的行。

我的第一个想法是长期运行的交易,即使是简单的SELECT(获得低廉的ACCESS SHARE锁)也可以阻止VACUUM正常工作。并行的20个线程可能会无限期地链接并锁定VACUUM。保持您的交易(及其锁)尽可能简短。并确保您的查询已优化,并且不会锁定不必要的行。

还有一点要注意:transaction isolation级别SERIALIZABLEREPEATABLE READ使得VACUUM清理变得更加困难。默认的READ COMMITTED模式的限制较少,但仍可以按照讨论阻止VACUUM

相关: