PostgreSQL - 如何在事务块外运行VACUUM?

49 投票
9 回答
31296 浏览
提问于 2025-04-15 12:21

我正在使用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)

9 个回答

5

另外,你还可以通过以下方式获取Vacuum或Analyse的消息:

>> print conn.notices #conn is the connection object

这个命令会打印出一个包含像Vacuum和Analyse这样的查询日志消息的列表:

INFO:  "usuario": processados 1 de 1 páginas, contendo 7 registros vigentes e 0 registros não vigentes; 7 registros amostrados, 7 registros totais estimados   
INFO:  analisando "public.usuario"

这对数据库管理员来说非常有用哦 ^^

6

如果你也尝试过很多方法来解决这个问题但都没有成功,可能和我遇到的情况一样:我在一次 execute() 调用中写了两个(或更多)SQL语句。结果发现,Postgres会在第一个语句后(用 ; 分隔)重置任何自动提交或隔离设置。最后我在这里找到了解决办法:https://github.com/psycopg/psycopg2/issues/1201

所以不要像这样做:

cursor.execute("SELECT 1; VACUUM FULL")

而是要这样做:

cursor.execute("SELECT 1")
cursor.execute("VACUUM FULL")
83

经过更多的搜索,我发现了psycopg2连接对象的一个属性,叫做isolation_level。结果发现,把这个值改成0可以让你跳出事务块。把上面那个类的vacuum方法改成下面这样就能解决这个问题。需要注意的是,我还把隔离级别设置回之前的值,以防万一(默认似乎是1)。

def vacuum(self):
    old_isolation_level = self.conn.isolation_level
    self.conn.set_isolation_level(0)
    query = "VACUUM FULL"
    self._doQuery(query)
    self.conn.set_isolation_level(old_isolation_level)

这篇文章(在页面的末尾附近)对这个上下文中的隔离级别做了简单的解释。

撰写回答