Pergunta

Eu estou usando Python com psycopg2 e eu estou tentando executar um VACUUM completo após uma operação diária que insere vários milhares de linhas. O problema é que quando eu tento executar o comando VACUUM dentro do meu código eu recebo o seguinte erro:

psycopg2.InternalError: VACUUM cannot run inside a transaction block

Como faço para executar este a partir do código fora de um bloco de transação?

Se ele faz a diferença, eu tenho uma classe DB abstração simples, um subconjunto do que é exibido abaixo de contexto (não executável, exceção de manipulação e docstrings omitidos e ajustes de linha abrangendo feito):

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)
Foi útil?

Solução

Depois de mais procura descobri a propriedade isolation_level do objeto de conexão psycopg2. Acontece que mudar isso para 0 vai movê-lo para fora de um bloco de transação. Alterando o método de vácuo da classe acima para as seguintes resolve-lo. Note que eu também definir o nível de volta isolamento ao que era anteriormente apenas no caso (parece ser 1 por padrão).

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)

Este artigo (perto do fim nessa página) fornece uma breve explicação de isolamento níveis neste contexto.

Outras dicas

Além disso, você também pode obter as mensagens dadas pelo vácuo ou Analisar usando:

>> print conn.notices #conn is the connection object

este comando imprimir uma lista com a mensagem de log de consultas como vácuo e Análise:

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"

Isto pode ser útil ao DBAs ^^

Enquanto vácuo total é questionável nas versões atuais do PostgreSQL, forçando um 'vácuo analisar' ou 'reindexação' depois de certas ações massivas pode melhorar o desempenho, ou o uso do disco limpeza. Isto é específico do PostgreSQL, e precisa ser limpo para fazer a coisa certa para outras bases de dados.

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)

Infelizmente o proxy ligação fornecida pelo Django não fornece acesso a set_isolation_level.

Nota se você estiver usando Django com o Sul para executar uma migração você pode usar o seguinte código para executar um 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()

Eu não sei psycopg2 e PostgreSQL, mas apenas APSW e SQLite, então eu acho que não pode dar uma ajuda "psycopg2".

Mas costuras para mim, que o PostgreSQL pode funcionar semelhante como SQLite faz, ele tem dois modos de operação:

  • Fora de um bloco de transação: Este é semanticamente equivalente a ter um bloco de transação em torno de cada operação SQL única
  • Dentro de um bloco de transação, que é marcado por "BEGIN TRANSACTION" e acabou por "TRANSACTION END"

Quando este for o caso, o problema pode estar dentro do psycopg2 camada de acesso. Quando isso acontece normalmente operam de forma que as transações são implicitamente inserido até um commit é feito, não poderia haver "forma padrão" para fazer um vácuo.

Claro que poderia ser possível, que "psycopg2" tem o seu método especial "vazio", ou um modo de operação especial, onde há transações implícitas são iniciados.

Quando há essa possibilidade existe, permanece uma única opção (sem alterar a camada de acesso ;-)):

A maioria dos bancos de dados têm um programm shell para acessar o banco de dados. O programa pode ser executado este programa concha com um tubo (inserindo o vácuo comando no shell), utilizando, assim, a concha Programa para fazer o vácuo. Uma vez que a vácuo é uma operação lenta, tais como, o início de um Programa externa será neglectible. Claro, o programa real deve comprometer todo o trabalho uncommited antes, outra pessoa poderia haver uma situação dead-lock -. O vácuo deve esperar até o final de sua última transação

Não faça isso - você não precisa VACUUM FULL. Na verdade, se você executar versão relativamente recente do Postgres (digamos> 8,1), você não precisa mesmo de executar VACUUM simples manualmente.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top