8

我正在使用 Python 和psycopg22.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)中运行查询时,也会发生同样的效果,但在这种情况下,查询会停留Idle状态并创建目标表。

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

4

3 回答 3

0

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

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


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

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

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

问题可能与以下有关:

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

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

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

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

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

你可以做两件事:

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

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


.commit()解决方案

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

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

将此选项设置为False您需要调用conn.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)""")

传统方式

如果您不想自动提交事务,则需要.commit()execute.

于 2020-09-06T16:49:27.207 回答
0

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

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

于 2020-12-01T20:51:58.390 回答
-1

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

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

于 2020-08-06T19:41:24.817 回答