Domanda

Sto usando Python con psycopg2 e sto cercando di eseguire un VACUUM completo dopo un'operazione quotidiana che inserisce diverse migliaia di righe. Il problema è che quando provo ad eseguire il comando VACUUM all'interno del mio codice ottengo il seguente errore:

psycopg2.InternalError: VACUUM cannot run inside a transaction block

Come eseguo questo dal codice al di fuori di un blocco di transazione?

Se fa la differenza, ho una semplice classe di astrazione DB, un sottoinsieme del quale viene visualizzato di seguito per il contesto (non eseguibile, gestione delle eccezioni e docstring omessi e rettifiche di spanning della linea eseguite):

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)
È stato utile?

Soluzione

Dopo ulteriori ricerche ho scoperto la proprietà isolation_level dell'oggetto di connessione psycopg2. Si scopre che cambiando questo in 0 si uscirà da un blocco di transazione. La modifica del metodo del vuoto della classe sopra in quella seguente lo risolve. Si noti che ho anche ripristinato il livello di isolamento su quello che era precedentemente nel caso (sembra essere 1 per impostazione predefinita).

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)

Questo articolo (vicino alla fine di quella pagina) fornisce una breve spiegazione dell'isolamento livelli in questo contesto.

Altri suggerimenti

Inoltre, puoi anche ottenere i messaggi forniti da Vacuum o Analizza usando:

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

questo comando stampa un elenco con il messaggio di registro di query come Vacuum e Analizza:

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"

Questo può essere utile ai DBA ^^

Mentre il vuoto completo è discutibile nelle attuali versioni di postgresql, forzare un '' analisi del vuoto '' o 'reindicizzare' dopo alcune azioni massicce può migliorare le prestazioni o ripulire l'utilizzo del disco. Questo è specifico di postgresql e deve essere ripulito per fare la cosa giusta per altri database.

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)

Sfortunatamente il proxy di connessione fornito da django non fornisce l'accesso a set_isolation_level.

Nota se stai usando Django con South per eseguire una migrazione puoi usare il seguente codice per eseguire un 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()

Non conosco psycopg2 e PostgreSQL, ma solo apsw e SQLite, quindi penso di non poter dare un " psycopg2 " aiuto.

Ma mi sembra che PostgreSQL possa funzionare in modo simile a SQLite, ha due modalità operative:

  • Fuori da un blocco di transazione: questo è semanticamente equivalente ad avere un blocco di transazione attorno a ogni singola operazione SQL
  • All'interno di un blocco di transazione, contrassegnato da " INIZIA TRANSAZIONE " e terminato con " END TRANSACTION "

In questo caso, il problema potrebbe essere all'interno del livello di accesso psycopg2. Quando funziona normalmente in modo da inserire implicitamente le transazioni fino a quando non viene effettuato un commit, non ci potrebbe essere "modo standard". fare il vuoto.

Ovviamente potrebbe essere possibile che "psycopg2" ha il suo speciale "vuoto" metodo o una modalità operativa speciale, in cui non vengono avviate transazioni implicite.

Quando non esiste tale possibilità, rimane una sola opzione (senza cambiare il livello di accesso ;-)):

La maggior parte dei database ha un programma shell per accedere al database. Il programma potrebbe eseguire questo programma di shell con una pipe (inserendo il comando di vuoto nella shell), utilizzando quindi il programma di shell per creare il vuoto. Poiché il vuoto è un'operazione lenta in quanto tale, l'avvio di un programma esterno sarà trascurabile. Ovviamente, il programma attuale dovrebbe impegnare tutto il lavoro senza impegno prima, altrimenti potrebbe esserci una situazione di dead-lock - il vuoto deve attendere fino alla fine dell'ultima transazione.

Non farlo - non è necessario VACUUM FULL. In realtà se esegui una versione piuttosto recente di Postgres (diciamo > 8.1) non hai nemmeno bisogno di eseguire VACUUM manualmente manualmente.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top