我正在使用带有psycopg2的Python,并且我试图在每天插入数千行的操作之后运行完整的VACUUM
。问题是,当我尝试在我的代码中运行VACUUM
命令时,我收到以下错误:
psycopg2.InternalError: VACUUM cannot run inside a transaction block
如何从事务块外的代码运行它?
如果它有所不同,我有一个简单的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)
答案 0 :(得分:52)
经过更多搜索后,我发现了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)
This article(在该页面的末尾附近)提供了此上下文中隔离级别的简要说明。
答案 1 :(得分:4)
此外,您还可以使用以下方法获取Vacuum或Analyze提供的消息:
>> print conn.notices #conn is the connection object
此命令打印一个列表,其中包含查询的日志消息,如Vacuum和Analyze:
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 ^^
很有用答案 2 :(得分:4)
虽然在当前版本的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)
不幸的是,django提供的连接代理不提供对set_isolation_level的访问。
答案 3 :(得分:2)
请注意,如果您使用Django with South执行迁移,则可以使用以下代码执行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()
答案 4 :(得分:2)
对于尝试了解决此问题的所有建议但没有成功的其他任何人,您可能会遭受与我相同的命运:我在一次 execute()
调用中有 2 个(或更多)SQL 语句。事实证明,Postgres 本身会在第一条语句(由 ;
分隔)之后重置任何自动提交/隔离。我终于在这里找到了解决方案:https://github.com/psycopg/psycopg2/issues/1201
所以不要做这样的事情:
cursor.execute("SELECT 1; VACUUM FULL")
改为:
cursor.execute("SELECT 1")
cursor.execute("VACUUM FULL")
答案 5 :(得分:1)
我不知道psycopg2和PostgreSQL,但只有apsw和SQLite,所以我觉得我不能给“psycopg2”帮助。
但它对我来说,PostgreSQL可能与SQLite类似,它有两种操作模式:
在这种情况下,问题可能出在访问层psycopg2内部。当它正常运行时,交易被隐含地插入,直到提交为止,可能没有“标准方法”来实现真空。
当然有可能,“psycopg2”有其特殊的“真空”方法,或特殊的操作模式,没有启动隐式事务。
如果不存在这样的可能性,则只保留一个选项(不更改访问层;-)):
大多数数据库都有一个shell程序来访问数据库。该程序可以使用管道运行此shell程序(将vacuum命令输入shell),从而使用shell程序来实现真空。由于真空是一个缓慢的操作,外部程序的启动将是可以忽略的。当然,实际程序应该在之前完成所有未完成的工作,否则可能会出现死锁情况 - 真空必须等到最后一次交易结束。
答案 6 :(得分:-3)
不要这样做 - 你不需要VACUUM FULL。实际上如果你运行稍微版本的Postgres(比如说> 8.1),你甚至不需要手动运行普通的VACUUM。