Frage

Ich verwende Python mit psycopg2 und ich versuche, eine vollständige VACUUM nach einem täglichen Betrieb laufen zu lassen, die mehr tausend Zeilen einfügt. Das Problem ist, dass, wenn ich versuche, den VACUUM Befehl in meinem Code auszuführen bekomme ich folgende Fehlermeldung:

psycopg2.InternalError: VACUUM cannot run inside a transaction block

Wie kann ich laufen diese aus dem Code außerhalb eines Transaktionsblock?

Wenn es einen Unterschied macht, ich habe eine einfache DB Abstraktion Klasse, eine Teilmenge von denen unten Kontext angezeigt wird (nicht runnable, Ausnahmebehandlung und Docstrings weggelassen und Linie Spanning Anpassung vorgenommen):

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)
War es hilfreich?

Lösung

Nach mehr Suche habe ich die isolation_level Eigenschaft des psycopg2 Verbindungsobjekt entdeckt. Es stellt sich heraus, dass dies zu 0 ändern, werden Sie aus einem Transaktionsblock bewegen. Ändern des Vakuums Verfahren der obigen Klasse folgender löst es. Beachten Sie, dass ich gesetzt auch die Isolationsstufe zurück zu dem, was es war bisher nur für den Fall (scheint standardmäßig zu 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)

Dieser Artikel (am Ende auf dieser Seite) eine kurze Erläuterung der Isolation Ebene in diesem Zusammenhang.

Andere Tipps

Darüber hinaus können Sie auch die Meldungen, die vom Vakuum gegeben erhalten oder Analysieren mit:

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

Mit diesem Befehl eine Liste mit der Log-Nachricht von Abfragen wie Vakuum-Druck und 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"

Dies ist auf die DBAs nützlich sein ^^

Während Vakuum voll fragwürdig ist in aktuellen Versionen von postgresql, zwingt ein ‚Vakuum analysieren‘ oder ‚indiziert‘ nach bestimmten massiven Aktionen kann die Leistung verbessern oder reinigt Festplattennutzung auf. Dies ist postgresql spezifisch, und muss das Richtige für andere Datenbanken zu tun gereinigt.

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)

Leider ist die Verbindung Proxy von django bereitgestellt bietet keinen Zugriff auf set_isolation_level.

Beachten Sie, wenn Sie mit Django mit Süd eine Migration durchführen Sie den folgenden Code verwenden, um eine VACUUM ANALYZE auszuführen.

def forwards(self, orm):

    db.commit_transaction()
    db.execute("VACUUM ANALYZE <table>")

    #Optionally start another transaction to do some more work...
    db.start_transaction()

Ich weiß nicht, psycopg2 und PostgreSQL, aber nur apsw und SQLite, so dass ich denke, ich kann eine „psycopg2“ Hilfe nicht geben.

Aber es Nähte zu mir, dass PostgreSQL ähnlich funktionieren könnte wie SQLite der Fall ist, es hat zwei Betriebsmodi:

  • Außerhalb eines Transaktionsblock: Dies ist semantisch äquivalent einem Transaktionsblock um jede einzelne SQL-Operation haben
  • Innerhalb einer Transaktion blockieren, die von „BEGIN TRANSACTION“ und endete mit „END TRANSACTION“
  • markiert

Wenn dies der Fall ist, das Problem innerhalb der Zugriffsschicht psycopg2 sein könnte. Wenn es in der Regel in einer Art und Weise funktioniert, die Transaktionen implizit eingeführt werden, bis eine Festschreibung gemacht wird, könnte es keine „Standardverfahren“, um ein Vakuum zu machen.

Natürlich könnte es möglich sein, dass „psycopg2“ hat seine besondere „Vakuum“ Methode oder einen speziellen Betriebsmodus, in dem keine impliziten Transaktionen gestartet werden.

Wenn keine solche Möglichkeiten existieren, bleibt dort eine einzige Option (ohne die Zugriffsschicht zu ändern ;-)):

Die meisten Datenbanken haben ein Shell-Programm auf die Datenbank zuzugreifen. Das Programm könnte diese Shell-Programm mit einem Rohr (Eingabe der Vakuum-Befehl in die Schale) laufen, wodurch die Schale Programm unter Verwendung des Vakuum zu machen. Da Vakuum ein langsamer Vorgang als solcher ist, wird der Start eines externen Programm vernachlässigbar sein. Natürlich sollte das eigentliche Programm, bevor alle Uncommited Arbeit begehen, sonst eine Deadlock Situation da sein könnte -. Das Vakuum bis zum Ende der letzten Transaktion warten muß,

Sie es nicht tun - Sie brauchen nicht VACUUM FULL. Eigentlich, wenn Sie etwas aktuellere Version von Postgres laufen (sagen wir mal> 8.1) Sie haben nicht einmal schlicht VACUUM manuell ausgeführt werden müssen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top