【问题标题】:What are the consequences of not ending a database transaction?不结束数据库事务的后果是什么?
【发布时间】:2015-11-19 22:08:56
【问题描述】:

我在我的应用程序代码中发现了一个错误,我已经启动了一个事务,但从未提交或回滚。定期使用连接,每隔 10 秒左右读取一些数据。在pg_stat_activity表中,它的状态被报告为“idle in transaction”,它的backend_start时间是一个多星期前。

这对数据库有什么影响?它是否会导致额外的 CPU 和 RAM 使用?它会影响其他连接吗?这种状态能持续多久?

我正在使用 postgresql 9.1 和 9.4。

【问题讨论】:

  • 影响:1.您的数据对其他事务不可见 2.如果您最终不提交 - 您将丢失数据。
  • @zerkms 我对服务器上的处理影响更感兴趣:我意识到所做的任何更改对其他连接都不可见(尽管在这种情况下,它只是读取数据,从不修改任何内容)
  • 丢失数据最终不是问题,因为您始终可以使用 SAVEPOINTS。

标签: postgresql transactions


【解决方案1】:

由于你只有SELECT,所以影响有限。对于任何写入操作来说,这种情况更为严重,其中更改在提交之前对任何其他事务都是不可见的 - 如果从未提交,则会丢失。

它确实消耗一些 RAM 并且永久地占用您允许的连接之一(这可能会或可能不会重要)。

长时间运行的事务的一个更严重的后果是:它阻止VACUUM 完成它的工作,因为仍然有一个旧事务可以看到旧行。系统将开始膨胀。

特别是,SELECT 在所有引用的表上获取ACCESS SHARE 锁(阻塞最少)。这不会干扰其他 DML 命令,如 INSERTUPDATEDELETE,但它会阻止 DDL 命令 以及 TRUNCATEVACUUM(包括 autovacuum 作业)。 See "Table-level Locks" in the manual.

如果它保持打开足够长的时间/您足够快地烧掉足够多的 XID,从长远来看,它还会干扰各种 复制 解决方案并导致 事务 ID 环绕。更多关于 in the manual on "Routine Vacuuming".

如果其他事务被阻止提交并且那些已经获得了自己的锁,则阻塞效果会蘑菇。等等。

您可以(几乎)无限期地保持事务打开 - 直到连接关闭(很明显,当服务器重新启动时也会发生这种情况。)
但永远不要让事务打开超过需要的时间。

【讨论】:

  • 它只是阻止事务中使用的表的 VACUUM 还是所有表?
  • 实际上,VACUUM 可以处理被虚拟 xid 锁定为ACCESS SHARE 的表。但是,它不能截断它以将空间释放回操作系统。如果事务是SERIALIZABLE,或者有一个当前正在运行的语句,它不能删除由并发更新/删除创建的死行。自己试试。创建一个带有虚拟行的表。启动一个 xact 并从表中选择以锁定它。开始另一个 xact 并删除一半的行,但不要提交。 VACUUM VERBOSE 来自另一个会话。它将删除死行。
  • SERIALIZABLEREPEATABLE READ xacts 会阻止真空去除死行。它只是一个没有活动快照的READ COMMITTED xact,可以让真空继续进行。其他一些事情,比如WITH HOLD 光标、准备好的 xact 等也可以。
  • pg_stat_statements 中检查backend_xmin 以查看后端是否阻止了vacuum。它仅适用于 9.4 及更高版本。
  • 1 @CraigRinger vaccum 仅对该事务中的表停止工作是不正确的,它将停止对所有表工作,因为当有一个正在运行的事务时,之后创建的死元组将不会通过真空清理所有表,因为事务 id 是全局生成的,它检查的事务 id 小于最旧事务的事务 id
【解决方案2】:

对系统有两个主要影响。

在这些事务中使用的表:

  1. 不是vacuumed,这意味着它们没有被“清理”并且它们的统计信息没有更新,这可能会导致糟糕(=慢)的执行计划
  2. 无法使用ALTER TABLE 更改

【讨论】:

    猜你喜欢
    • 2010-11-01
    • 1970-01-01
    • 2019-01-24
    • 2018-10-05
    • 1970-01-01
    • 2013-08-31
    • 2011-02-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多