我正在将 Python 与 psycopg2 一起使用,并尝试VACUUM在插入数千行的日常操作后运行完整的操作。问题是,当我尝试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)
您遇到的问题源于尝试在事务块内执行 VACUUM FULL。VACUUM 命令,包括 VACUUM FULL,不能在事务块内执行,因为它们需要对表进行独占锁定,而这在事务中无法实现。为了解决这个问题,您需要确保在任何事务块之外执行 VACUUM 命令。
VACUUM FULL
您可以通过在游标上设置 autocommit 为 True 来实现在代码中执行 VACUUM 命令而不启动新的事务。这里是如何修改您的代码以在不启动新事务的情况下执行 VACUUM 命令的示例:
autocommit
True
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 可能是一个昂贵的操作,特别是在大表上,可能会导致一些性能影响,因此请谨慎使用。