我在psycopg2中使用Python,在一次插入数千行的日常操作之后,我试图运行一个完整的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)
8条答案
按热度按时间i1icjdpr1#
对于其他任何一个围绕这个问题尝试了所有建议都没有成功的人来说,你可能会遭受和我一样的命运:我在一个
execute()
调用中有2个(或更多)SQL语句,结果Postgres自己在第一个语句(由;
分隔)之后重置了所有自动提交/隔离。https://github.com/psycopg/psycopg2/issues/1201所以不要做这样的事情:
相反,应:
gdrx4gfi2#
此外,您还可以使用以下方法获得真空或分析给出的消息:
此命令打印包含查询(如真空和分析)日志消息的列表:
这对DBA很有用^^
ou6hu8tu3#
尽管在当前版本的postgresql中vacuum full是有问题的,但是在某些大规模操作之后强制执行“vacuum analyze”或“reindex”可以提高性能,或者清理磁盘使用。这是postgresql特有的,需要清理才能对其他数据库做正确的事情。
不幸的是django提供的连接代理不提供set_isolation_level的访问权限。
vybvopom4#
注意如果你使用Django和South来执行迁移,你可以使用下面的代码来执行
VACUUM ANALYZE
。n8ghc7c15#
我不知道psycopg 2和PostgreSQL,但只有apsw和SQLite,所以我想我不能给予一个“psycopg 2”的帮助。
但在我看来,PostgreSQL的工作原理可能与SQLite类似,它有两种操作模式:
在这种情况下,问题可能出在访问层psycopg 2内部。当它以隐式插入事务直到提交的方式正常运行时,可能没有“标准方法”来制造真空。
当然,“psycopg 2”有其特殊的“vacuum”方法或特殊的操作模式,在这种方法中不启动隐式事务。
当不存在这样的可能性时,保留一个单一选项(不改变接入层;- )):
大多数数据库都有一个shell程序来访问数据库。这个程序可以通过管道来运行这个shell程序(将vacuum-command输入shell),从而使用shell程序来执行vacuum。由于vacuum-command本身是一个缓慢的操作,因此外部程序的启动将被忽略。当然,实际程序应在此之前提交所有未提交的工作,否则可能会出现死锁情况-真空必须等到最后一个事务结束。
r1zk6ea16#
虽然这不是OP的确切情况,但我也遇到了这种情况。结果表明,它与连接用作上下文时打开的隐式事务有关。例如,如果OP的代码类似于以下内容,即使使用正确的隔离级别,它也会因为不同的原因而遇到完全相同的错误:
解决方案是不使用连接作为上下文:
2wnc66cl7#
不要这样做-你不需要VACUUM FULL。实际上,如果你运行最近版本的Postgres(比如说〉8.1),你甚至不需要手动运行普通的VACUUM。
sbtkgmzw8#
经过更多的搜索,我发现了psycopg2连接对象的isolation_level属性。原来将其更改为
0
会将您移出事务块。将上述类的vacuum方法更改为以下方法解决了这个问题。注意,我还将隔离级别设置回以前的值,以防万一(默认情况下似乎是1
)。This article(接近该页末尾)简要说明了此上下文中的隔离级别。