小能豆

PostgreSQL - 如何从事务块外部的代码运行 VACUUM?

python sql

我正在将 Python 与 psycopg2 一起使用,并尝试VACUUM在插入数千行的日常操作后运行完整的操作。问题是,当我尝试VACUUM在代码中运行该命令时,出现以下错误:

psycopg2.InternalError: VACUUM cannot run inside a transaction block

如何从事务块外部的代码运行它?

如果它有所不同,我有一个简单的数据库抽象类,下面显示了它的一个子集以供上下文(不可运行,省略了异常处理和文档字符串,并进行了行跨越调整):

class db(object):
    def __init__(dbname, host, port, user, password):
        self.conn = psycopg2.connect("dbname=%s host=%s port=%s \
                                      user=%s password=%s" \
                                      % (dbname, host, port, user, password))

        self.cursor = self.conn.cursor()

    def _doQuery(self, query):
        self.cursor.execute(query)
        self.conn.commit()

    def vacuum(self):
        query = "VACUUM FULL"
        self._doQuery(query)

阅读 64

收藏
2024-05-15

共1个答案

小能豆

您遇到的问题源于尝试在事务块内执行 VACUUM FULLVACUUM 命令,包括 VACUUM FULL,不能在事务块内执行,因为它们需要对表进行独占锁定,而这在事务中无法实现。为了解决这个问题,您需要确保在任何事务块之外执行 VACUUM 命令。

您可以通过在游标上设置 autocommitTrue 来实现在代码中执行 VACUUM 命令而不启动新的事务。这里是如何修改您的代码以在不启动新事务的情况下执行 VACUUM 命令的示例:

class db(object):
    def __init__(self, dbname, host, port, user, password):
        self.conn = psycopg2.connect("dbname=%s host=%s port=%s \
                                      user=%s password=%s" \
                                      % (dbname, host, port, user, password))
        self.cursor = self.conn.cursor()

    def _doQuery(self, query):
        self.cursor.execute(query)

    def vacuum(self):
        self.cursor.execute("SET autocommit TO ON")
        query = "VACUUM FULL"
        self._doQuery(query)

通过将 autocommit 设置为 True,您确保每个语句都被作为单独的事务执行,因此 VACUUM 命令不会在事务块内执行。但是,请记住,VACUUM FULL 可能是一个昂贵的操作,特别是在大表上,可能会导致一些性能影响,因此请谨慎使用。

2024-05-15