41

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

psycopg2.InternalError: VACUUM cannot run inside a transaction block

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

如果它有所作为,我有一个简单的 DB 抽象类,它的一个子集显示在下面的上下文中(不可运行,异常处理和文档字符串被省略,并且行跨越调整):

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)
4

7 回答 7

73

经过更多搜索,我发现了 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)

本文(接近该页的末尾)提供了在此上下文中的隔离级别的简要说明。

于 2009-06-19T12:18:49.390 回答
4

此外,您还可以使用以下方法获取 Vacuum 或 Analyze 给出的消息:

>> 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"

这对 DBA 很有用^^

于 2011-01-08T21:15:48.727 回答
4

虽然在当前版本的 postgresql 中,vacuum full 是有问题的,但在某些大规模操作之后强制执行“vacuum analyze”或“reindex”可以提高性能或清理磁盘使用情况。这是 postgresql 特有的,需要清理才能为其他数据库做正确的事情。

from django.db import connection
# Much of the proxy is not defined until this is done
force_proxy = connection.cursor()
realconn=connection.connection
old_isolation_level = realconn.isolation_level
realconn.set_isolation_level(0)
cursor = realconn.cursor()
cursor.execute('VACUUM ANALYZE')
realconn.set_isolation_level(old_isolation_level)

不幸的是,django 提供的连接代理不提供对 set_isolation_level 的访问。

于 2012-12-19T15:09:25.160 回答
4

对于其他尝试了有关此问题的所有建议但均未成功的其他人,您可能会遭受与我相同的命运:我在一次execute()调用中有 2 个(或更多)SQL 语句。事实证明,Postgres 本身会在第一条语句(由 a 分隔;)之后重置任何自动提交/隔离。我终于在这里遇到了解决方案:https ://github.com/psycopg/psycopg2/issues/1201

所以不要做这样的事情:

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

而是这样做:

cursor.execute("SELECT 1")
cursor.execute("VACUUM FULL")
于 2021-03-17T04:45:41.593 回答
2

请注意,如果您使用带有 South 的 Django 执行迁移,您可以使用以下代码执行VACUUM ANALYZE.

def forwards(self, orm):

    db.commit_transaction()
    db.execute("VACUUM ANALYZE <table>")

    #Optionally start another transaction to do some more work...
    db.start_transaction()
于 2014-05-15T17:18:53.957 回答
1

我不知道 psycopg2 和 PostgreSQL,但只知道 apsw 和 SQLite,所以我想我不能给出“psycopg2”的帮助。

但在我看来,PostgreSQL 可能像 SQLite 一样工作,它有两种操作模式:

  • 在事务块之外:这在语义上等同于在每个 SQL 操作周围都有一个事务块
  • 在事务块内,由“BEGIN TRANSACTION”标记并以“END TRANSACTION”结束

在这种情况下,问题可能出在访问层 psycopg2 内部。当它通常以隐式插入事务直到提交之前的方式运行时,可能没有“标准方式”来制造真空。

当然,“psycopg2”可能有其特殊的“真空”方法,或特殊的操作模式,其中不启动隐式事务。

当不存在这种可能性时,只有一个选项(不更改访问层;-)):

大多数数据库都有一个外壳程序来访问数据库。该程序可以使用管道运行这个shell程序(将vacuum命令输入到shell中),从而使用shell程序来制作真空。由于真空本身是一个缓慢的操作,外部程序的启动将是可以忽略的。当然,实际的程序应该先提交所有未提交的工作,否则可能会出现死锁情况——真空必须等到最后一个事务结束。

于 2009-06-19T11:59:33.097 回答
-3

不要这样做 - 你不需要 VACUUM FULL。实际上,如果您运行最新版本的 Postgres(比如说 > 8.1),您甚至不需要手动运行普通的 VACUUM。

于 2009-06-19T12:22:50.100 回答