【问题标题】:Postgres "CREATE TABLE AS (SELECT ...)" stuckPostgres“CREATE TABLE AS(SELECT ...)”卡住了
【发布时间】:2020-11-27 02:56:55
【问题描述】:

我使用 Python 和 psycopg2 2.8.6 对抗 Postgresql 11.6(也在 11.9 上尝试过)

当我运行查询时

CREATE TABLE tbl AS (SELECT (row_number() over())::integer "id", "col" FROM tbl2)

代码卡住了(cursor.execute 永远不会返回),用pg_terminate_backend 终止事务会从服务器中删除查询,但代码没有释放。然而在这种情况下,目标表被创建。

没有任何东西会锁定事务。内部SELECT 查询本身已经过测试,并且运行良好。

我尝试分析服务器上的线索,发现pg_stat_activity内部有以下内容:

  • 事务stateidle in transaction
  • wait_event_typeClient
  • wait_eventClientRead

当我在 SQL 编辑器 (pgModeler) 中运行查询时,会发生同样的效果,但在这种情况下,查询卡住 strong> 开启Idle 状态并创建目标表。

我不确定出了什么问题以及如何从这里开始。 谢谢!

【问题讨论】:

  • 在这里看起来类似的问题,stackoverflow.com/questions/11306583/…
  • 那么你的“标准 SQL 编辑器”也有同样的问题。信不信由你:如果会话在事务中空闲并且等待从客户端读取,这正是它正在做的事情。是客户感到困惑并坐以待毙而不是继续。
  • @LaurenzAlbe,它发生在这种特定类型的查询(查询本身很长,并且包含对约 500 列的引用)具有不同的数据库实例和表(也是长查询)和 2 种不同类型的 SQL编辑。也在 v11.7 上转载。它只发生在 CREATE TABLE AS SELECT 或 SELECT INTO 查询中,日志中没有报告任何特殊情况。有什么方法可以跟踪连接到底发生了什么以及为什么 Postgres 认为连接是等待并且客户端卡住了? Tnx
  • 您必须跟踪或调试客户端代码。如果查询时间过长,可能会有超时导致行为不端,但我只是猜测。如果在这两种情况下都使用了 psycopg2,那么问题可能就在那里。我可以保证这与数据库服务器无关。
  • SELECT (row_number() over())::integer "id", "col" FROM tbl2 返回什么? ;-) 另外,您是否期望表的副本或计算表随时间更新(VIEW)?

标签: python sql postgresql psycopg2 pgmodeler


【解决方案1】:

问题不可重现,您必须进行更多调查。您必须分享有关您的数据库表、python 代码和服务器操作系统的更多详细信息。

您还可以与我们分享 Python 附带的 strace,以便我们了解查询过程中实际发生的情况。


  • wait_event_type = Client:服务器进程正在等待来自用户应用程序的套接字上的某些活动,并且服务器期望发生一些独立于其内部进程的事情。 wait_event 会识别具体的等待点。

  • wait_event = ClientRead:等待ClientRead 的会话处理完最后一个查询并等待客户端发送下一个请求。这种会话可以阻止任何东西的唯一方法是它的状态是idle in transaction。所有的锁都被持有直到事务结束,一旦事务结束就不再持有任何锁。

  • Idle in transaction:活动可以是idle(即等待客户端命令)、idle in transaction(在BEGIN块内等待客户端)或命令类型名称,例如 SELECT。此外,如果服务器进程当前正在等待另一个会话持有的锁,则会附加等待。

问题可能与:

  • 网络问题
  • 在某个地方创建了相同的表名的未提交事务。
  • 事务未提交

您指出这不是提交问题,因为 SQL 编辑器执行相同操作,但在您的问题中您指定编辑器成功创建表。

在 pgModeler 中你看到 idle,这意味着 会话 是空闲的,而不是查询。

如果会话空闲,pg_stat_activity 的“查询”列显示该会话中最后执行的语句。 所以这仅仅意味着所有这些会话都使用 ROLLBACK 语句正确地结束了他们的事务。

如果会话保持状态idle in transaction 的时间更长,这始终是应用程序没有结束事务的应用程序错误。

你可以做两件事:

  • 设置idle_in_transaction_session_timeout 以便服务器在一段时间后自动回滚这些事务。这将防止锁被无限期持有,但您的应用程序将收到错误。

  • 如下图所示修复应用程序


.commit()解决方案

我发现重现该问题的唯一方法是省略 commit 操作。

psycopg2 模块与Python DB API 兼容,因此默认情况下自动提交功能处于关闭状态。

将此选项设置为False,您需要调用conn.commit 将任何待处理事务提交到数据库。

启用自动提交

您可以按如下方式启用auto-commit

import psycopg2

connection = None

try:
    connection = psycopg2.connect("dbname='myDB' user='myUser' host='localhost' password='myPassword'")
    connection.autocommit = True
except:
    print "Connection failed."

if(connection != None):
    cursor = connection.cursor()

    try:
        cursor.execute("""CREATE TABLE tbl AS (SELECT (row_number() over())::integer 'id', 'col' FROM tbl2)""")
    except:
        print("Failed to create table.")

with声明

您还可以使用with 语句自动提交事务:

with connection, connection.cursor() as cursor:  # start a transaction and create a cursor
    cursor.execute("""CREATE TABLE tbl AS (SELECT (row_number() over())::integer 'id', 'col' FROM tbl2)""")

传统方式

如果您不想自动提交事务,则需要在 execute 之后手动调用 .commit()

【讨论】:

  • 我看不出这个答案与提出的问题有什么关系。 SQL 编辑器的问题仍然存在——无论有没有事务。 (见 cmets)
【解决方案2】:

我在这里回答我自己的问题,以便对其他人有所帮助。

通过将tcp_keepalives_idle Postgres 设置从默认的 2 小时修改为 5 分钟解决了问题。

【讨论】:

    【解决方案3】:

    只需删除 SELECT... 周围的 ( )

    https://www.postgresql.org/docs/11/sql-createtableas.html

    【讨论】:

      猜你喜欢
      • 2013-12-27
      • 2013-06-29
      • 2010-11-27
      • 1970-01-01
      • 1970-01-01
      • 2020-02-08
      • 1970-01-01
      • 1970-01-01
      • 2018-12-28
      相关资源
      最近更新 更多