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

Way*_*rts 33 python sql postgresql psycopg2 vacuum

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

psycopg2.InternalError: VACUUM cannot run inside a transaction block
Run Code Online (Sandbox Code Playgroud)

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

如果它有所不同,我有一个简单的DB抽象类,下面显示了一个子集用于上下文(不是runnable,省略了异常处理和docstrings以及进行了行跨越调整):

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)
Run Code Online (Sandbox Code Playgroud)

Way*_*rts 55

经过更多搜索后,我发现了psycopg2连接对象的isolation_level属性.事实证明,将此更改为0将使您退出事务块.将上述类的真空方法改为以下解决方案.请注意,我还将隔离级别设置回原先的情况(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)
Run Code Online (Sandbox Code Playgroud)

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

  • 或者,避免使用魔术数字:`self.conn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)` (16认同)

tom*_*mbh 6

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

所以不要做这样的事情:

cursor.execute("SELECT 1; VACUUM FULL")
Run Code Online (Sandbox Code Playgroud)

相反,做:

cursor.execute("SELECT 1")
cursor.execute("VACUUM FULL")
Run Code Online (Sandbox Code Playgroud)


Die*_*aes 5

此外,您还可以使用以下命令获取 Vacuum 或 Analytics 给出的消息:

\n\n
>> print conn.notices #conn is the connection object\n
Run Code Online (Sandbox Code Playgroud)\n\n

此命令打印一个列表,其中包含 Vacuum 和 Analyse 等查询的日志消息:

\n\n
INFO:  "usuario": processados 1 de 1 p\xc3\xa1ginas, contendo 7 registros vigentes e 0 registros n\xc3\xa3o vigentes; 7 registros amostrados, 7 registros totais estimados   \nINFO:  analisando "public.usuario"\n
Run Code Online (Sandbox Code Playgroud)\n\n

这对 DBA 很有用 ^^

\n


Chr*_*kes 5

虽然在当前版本的 postgresql 中真空已满是有问题的,但在某些大规模操作后强制执行“真空分析”或“重新索引”可以提高性能或清理磁盘使用情况。这是 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)
Run Code Online (Sandbox Code Playgroud)

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