PostgreSQL - 如何在事务块外运行VACUUM?
我正在使用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)
这篇文章(在页面的末尾附近)对这个上下文中的隔离级别做了简单的解释。