【问题标题】:PostgreSQL connection closes unexpectedly when doing a large insert执行大型插入时 PostgreSQL 连接意外关闭
【发布时间】:2011-02-23 10:45:38
【问题描述】:

我正在使用之前从另一个数据库中选择的 ~11.000.000 行填充 PostgreSQL 表。我正在使用 Python 和 psycopg2。整个过程估计需要 1.5 小时才能完成。但是,大约 30 分钟后,我得到“连接意外关闭”异常。源代码如下所示:

incursor = indb.cursor()
incursor.execute("SELECT ...")
indb.commit() # (1) close transaction
outcursor = outdb.cursor()
rows = 0
for (col1, col2, col3) in incursor: # incursor contains ~11.000.000 rows
    outcursor.execute("INSERT ...", (col1, col2, col3)) # This fails after ~30 minutes
    row += 1
    if row % 100 == 0: # (2) Write data every 100 rows
         outcursor.close()
         outdb.commit()
         outcursor = outdb.cursor()
incursor.close()
outcursor.close()
outdb.commit()

我在第一次尝试失败后插入了(1)(2),假设打开的事务的时间上限约为 30 分钟,或者游标具有挂起插入的上限。似乎这些假设都不成立,错误出在其他地方。

两个数据库都存储在我通过主机端口转发连接的 VirtualBox 机器上。我在主机上运行程序。

这两个数据库仅用于测试目的,它们没有其他要管理的连接。也许我必须重写这个问题来解决这个问题,但我需要在其他地方进行非常耗时的插入(运行大约几天),所以我非常担心psycopg2 或 PostgreSQL 中的一些隐藏时间限制。

【问题讨论】:

  • 我认为问题可能出在配置中的 work_mem 变量中。 AFAIK 此变量设置一个连接允许的最大内存。检查日志应该有一个关于什么是错误的条目
  • 但是 SELECT 语句根本不起作用,不是吗?但我失去了与outdb 的联系。
  • 使用COPY 或更大的事务。在单个事务中仅执行 100 条记录,为您提供大约 110.000 个事务来完成整个工作。单个 7400rpm 驱动器每秒只能处理 120 次提交(除非它因为缓存而存在,否则会使其不可靠)。您当前的问题听起来像是网络问题。
  • 你在使用连接池吗?一些池有一个默认配置,如果在一定时间后没有返回,则会关闭连接,以避免连接泄漏。
  • work_mem 没有设置一个连接的最大内存——默认只有 1MB。

标签: python postgresql psycopg


【解决方案1】:

我不知道 postgresql 本身有任何这样的“隐藏”超时。 PostgreSQL 确实有statement_timeout,但如果你点击它,你应该在服务器日志中得到一个ERROR: canceling statement due to statement timeout(它也会记录取消的语句)。我不能为 psycopg2 说话。一定要检查服务器日志是否有任何相关的内容。

可能是网络问题?长时间运行的语句将是一个长时间保持空闲的 TCP 连接。也许您的端口转发会清除空闲超过 30 分钟的连接?也许您的 TCP 连接没有使用 keepalive。 Postgresql 有一些用于调整 TCP keepalive 的设置(tcp_keepalives_interval 等),您可能还需要进行一些内核/网络配置以确保它们实际启用。

例如我只是在这里尝试连接到我自己的机器,tcp_keepalives_interval 默认为 7200,即 2 小时。如果您的端口转发在 30 分钟后中断,则此默认设置不会执行。您可以覆盖客户端连接字符串中使用的设置(假设您可以直接旋转 conninfo 字符串),或者在用户/数据库属性或 postgresql.conf 中设置 GUC 变量。

见:

【讨论】:

    【解决方案2】:

    要插入数百万行,我会查看官方guide 来填充数据库并考虑使用copy

    【讨论】:

      【解决方案3】:

      我有一个更新成千上万行的 django 管理命令。一段时间后,我看到了同样的错误。我相信内存使用量超过了限制。不过不知道如何在命令中手动控制事务。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-01-25
        • 1970-01-01
        • 2014-01-08
        • 1970-01-01
        • 2018-04-29
        • 2020-12-23
        • 2013-05-31
        • 1970-01-01
        相关资源
        最近更新 更多