互联网上有一些消息来源坚称idle in transaction
连接可能会阻止真空清理死元组,以下是一些示例:
\n\n\n处于空闲事务状态的事务可以持有阻止其他查询的锁。它还可以防止 VACUUM(包括 autovacuum)清理死行,从而导致索引或表膨胀或事务 ID 环绕。
\n
\n\n长事务实际上不是问题 \xe2\x80\x93 如果必须存在长事务和许多小更改,问题就会开始。请记住:长事务可能会导致 VACUUM 无法清除死行。
\n
实际上,有很多,但从我的角度来看,这听起来绝对荒谬:在大多数情况下,事务隔离级别是读已提交,这反过来意味着不需要为此类事务保留死元组,而且,我找到了替代方案关于该主题的意见:
\n\n\n它并不是真正的长期事务,而是长期快照。当然,长时间运行的 select 或 insert 语句可以做到这一点。对于高于读提交的隔离级别,整个事务将保留快照直到其宕机,因此如果某些事务打开了一个可重复读事务,然后在没有提交的情况下休假,那将是一个问题。挂起的准备好的交易也会(如果您不知道什么是准备好的交易,那么您可能没有使用它们)。
\n
或Pavel Luzanov 在 Cybertec 博文下的评论:
\n\n\n我相信长事务的示例仅适用于可重复读取(或可序列化)隔离级别。但默认情况下 BEGIN 使用已提交读。因此,在第一个会话中的 SELECT 完成后,VACUUM 将在会话 2 中的后续 UPDATE、DELETE 命令之后删除表中的死行。
\n
@Bill Karwin在他的回答中实际上证实了这一点(谢谢!)
\n问题是:是否存在“有效”“非虚构”场景时idle in transaction
连接应被视为有害?(我不是在询问隔离级别高于已提交读的事务、事务或连接泄漏、长时间事务持有锁等)。
确实,事务本身并不会阻止 的进展VACUUM
。VACUUM
仅当满足以下两个条件之一时,事务才会被阻止:
该事务已分配一个事务 ID(即,它已修改该数据库中的某些内容)。
该事务保存数据库的快照。快照是一种数据结构,用于确定某个事务对哪些其他事务可见。快照保持打开状态
只要 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)
归档时间: |
|
查看次数: |
1126 次 |
最近记录: |