交易连接闲置的危害是一个神话吗?

And*_*lov 3 postgresql

互联网上有一些消息来源坚称idle in transaction连接可能会阻止真空清理死元组,以下是一些示例:

\n

极光用户指南

\n
\n

处于空闲事务状态的事务可以持有阻止其他查询的锁。它还可以防止 VACUUM(包括 autovacuum)清理死行,从而导致索引或表膨胀或事务 ID 环绕

\n
\n

Cyber​​tec 博客

\n
\n

长事务实际上不是问题 \xe2\x80\x93 如果必须存在长事务和许多小更改,问题就会开始。请记住:长事务可能会导致 VACUUM 无法清除死行

\n
\n

实际上,有很多,但从我的角度来看,这听起来绝对荒谬:在大多数情况下,事务隔离级别是读已提交,这反过来意味着不需要为此类事务保留死元组,而且,我找到了替代方案关于该主题的意见

\n
\n

它并不是真正的长期事务,而是长期快照。当然,长时间运行的 select 或 insert 语句可以做到这一点。对于高于读提交的隔离级别,整个事务将保留快照直到其宕机,因此如果某些事务打开了一个可重复读事务,然后在没有提交的情况下休假,那将是一个问题。挂起的准备好的交易也会(如果您不知道什么是准备好的交易,那么您可能没有使用它们)。

\n
\n

Pavel Luzanov 在 Cyber​​tec 博文下的评论

\n
\n

我相信长事务的示例仅适用于可重复读取(或可序列化)隔离级别。但默认情况下 BEGIN 使用已提交读。因此,在第一个会话中的 SELECT 完成后,VACUUM 将在会话 2 中的后续 UPDATE、DELETE 命令之后删除表中的死行。

\n
\n

@Bill Karwin他的回答中实际上证实了这一点(谢谢!)

\n

问题是:是否存在“有效”“非虚构”场景时idle in transaction连接应被视为有害?(我不是在询问隔离级别高于已提交读的事务、事务或连接泄漏、长时间事务持有锁等)。

\n

Lau*_*lbe 5

确实,事务本身并不会阻止 的进展VACUUMVACUUM仅当满足以下两个条件之一时,事务才会被阻止:

  1. 该事务已分配一个事务 ID(即,它已修改该数据库中的某些内容)。

  2. 该事务保存数据库的快照。快照是一种数据结构,用于确定某个事务对哪些其他事务可见。快照保持打开状态

    • 只要 SQL 语句正在运行(因此长时间运行的查询可能会阻止VACUUM进度)

    • 当有一个光标打开时

    • 在事务的整个持续时间内,处于REPEATABLE READ或隔离级别SERIALIZABLE

您可以使用我有关该主题的文章中的查询来查看是否存在阻止VACUUM的进度的事务:

SELECT pid, datname, usename, state, backend_xmin, backend_xid
FROM pg_stat_activity
      /* holds a snapshot */
WHERE backend_xmin IS NOT NULL
      /* has a transaction ID */
   OR backend_xid IS NOT NULL
ORDER BY greatest(age(backend_xmin), age(backend_xid)) DESC;
Run Code Online (Sandbox Code Playgroud)