当前位置: 首页 > 知识库问答 >
问题:

postgreql中的活元组/死元组数量多/真空不工作

师建德
2023-03-14

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

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

> < li>

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

select查询--基于某些id进行选择

从shard_id=1的subscriber_offset_manager中选择*;

update query--为此选定的碎片id更新其他列

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

一个更有趣的观察:-当我停止我的java应用程序,然后做全真空,它工作正常(行数和活元组变得相等)。所以如果我们从java应用程序中连续选择和更新,就有问题。-

问题/问题

这些活元组有时会变成死元组,过了一段时间又会活起来。

由于上述行为,从表中选择需要时间并增加服务器上的负载,因为那里有很多活/死元组。

共有3个答案

阮梓
2023-03-14

毕竟可能存在锁,您的查询可能会误导:

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

pg_locks.pid 可以为 NULL,则连接将消除行。Postgres 9.3 的手册:

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

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

这个简单的查询有什么收获吗?

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

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

DETAIL:  67720 dead row versions cannot be removed yet.

这反过来会导致应用程序逻辑/查询出现问题,锁定的行数超过了需要。

我的第一个想法是长时间运行的事务,其中甚至一个简单的< code>SELECT(获得一个低级的< code>ACCESS SHARE锁)就可以阻止< code>VACUUM完成它的工作。并行的20个线程可能会连锁并无限期地锁定< code>VACUUM。让您的事务(及其锁)尽可能简短。并确保您的查询得到优化,不要锁定不必要的行。

还有一点需要注意:事务隔离级别<code>SERIALIZABLE</code>或<code>REPEATABLE READ</code>使<code>VACUUM</code>更难清理。默认的<code>READ COMMITTED</code>模式限制性较小,但<code>VACUUM</code>仍可以被阻止,如所讨论的。

相关:

  • 不结束数据库事务的后果是什么
  • Postgres更新…限制1
  • VACUUM VERBOSE输出,不可删除的“死区版本还不能删除”
全誉
2023-03-14

我把问题☺。

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

线程1 -

    < li >打开Hibernate会话 < li >对表A进行一些查询 < li >从subscriber_offset_manager中选择 < li >更新subscriber_offset_manager。 < li >关闭会话。

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

线程 2 -

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

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

此外,我们已经重新创建了这个问题很多次,并尝试了这个解决方案,它起作用了。

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

    < li >为什么postgres不显示任何与表“subscriber_offset_manager”相关的数据。 < li >如果我们使用psql对表A运行select,而不是运行Thread-2,则不会再次出现此问题。 < li >为什么postgres以这种方式使用jdbc。

还有一些令人振奋的观察:

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

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

邹高懿
2023-03-14

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

> 长时间运行的交易。

未提交的已准备好的事务。

过时的复制插槽。

有关详细信息,请参阅我的博客文章。

 类似资料:
  • 问题内容: 有一个表,其中有200行。但是显示的活动元组的数量不止于此(约60K)。 但是从pg_stat_activity和pg_locks可以看出,我们无法跟踪任何打开的连接。 我也在这张桌子上尝试了全真空,结果如下: 一直没有删除任何行 有时所有的活动元组变成死元组。 这是输出。 10秒后 我们的应用程序如何查询此表。 我们的应用程序通常选择一些行,并根据一些业务计算来更新该行。 选择查询

  • 问题内容: 有一个表,其中有200行。但是显示的活动元组的数量不止于此(约60K)。 但是从pg_stat_activity和pg_locks可以看出,我们无法跟踪任何打开的连接。 我也在这张桌子上尝试了全真空,结果如下: 一直没有删除任何行 有时,所有的活动元组都变成死元组。 这是输出。 10秒后 我们的应用程序如何查询此表。 我们的应用程序通常选择一些行,并根据一些业务计算来更新该行。 选择查

  • 我想从包含每个组中元素数量的向量创建一个包含每个元素的组标识符的向量。 例子: 我正在寻找一个向量如下: 我找到了一个涉及循环的解决方案: 但这看起来不太优雅。欢迎提出任何改进建议。

  • 问题内容: 我有一个功能: 排队 resultArray.append(tempDict) 我有一个错误: 调用中缺少参数“ ccomments”的参数 为什么?请帮助.... 问题答案: 在我看来,就像对待元组有点像可变参数,并试图扩展元组以匹配其自身的参数。它抱怨您的第二个参数,因为它只期待一个。我没有在任何地方看到这种行为的记录,因此我想说这是Swift中的错误。 使用追加运算符似乎没有这个

  • 我有一个数组,看起来像:。而将始终保持常数。我希望x每迭代增加100。 我就是这么做的: null null 正如您所看到的,它不是在增加值。它总是只是插入。在第一个名为pies的对象中,我希望和下一个名为cakes的对象为。 我该怎么做?

  • 问题内容: 根据用户提交的内容,数组中的某些元素是空字符串。我需要删除那些元素。我有这个: 但这是行不通的。仍然有空元素。我也尝试过使用该功能,但是结果是一样的。 问题答案: 在处理字符串数组时,您可以简单地使用,它可以方便地为您处理所有这一切: 请记住, 如果未提供回调 ,则将删除所有等于(请参见转换为boolean)数组的条目。因此,如果您需要保留元素,即确切的string ,则需要一个自定义