Question

J'utilise Python avec psycopg2 et j'essaie d'exécuter un VACUUM complet après une opération quotidienne qui insère plusieurs milliers de lignes. Le problème est que lorsque j'essaie d'exécuter la commande VACUUM dans mon code, l'erreur suivante apparaît:

psycopg2.InternalError: VACUUM cannot run inside a transaction block

Comment puis-je l'exécuter à partir du code situé en dehors d'un bloc de transaction?

Si cela fait une différence, j'ai une simple classe d'abstraction de base de données, dont un sous-ensemble est affiché ci-dessous pour le contexte (non exécutable, gestion des exceptions et docstrings omis et ajustements de réglage de ligne effectués):

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)
Était-ce utile?

La solution

Après plus de recherches, j'ai découvert la propriété isolation_level de l'objet de connexion psycopg2. Il s'avère que changer ceci en 0 vous fera sortir d'un bloc de transaction. Changer la méthode de vide de la classe ci-dessus pour la suivante résout le problème. Notez que j'ai également redéfini le niveau d'isolation sur ce qu'il était auparavant, au cas où (il semble que ce soit 1 par défaut).

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)

Cet article (à la fin de cette page) fournit une brève explication de l'isolement. niveaux dans ce contexte.

Autres conseils

De plus, vous pouvez également obtenir les messages donnés par le vide ou l'analyse à l'aide de:

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

cette commande affiche une liste avec le message de journal de requêtes telles que Vacuum et 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"

Cela peut être utile aux DBA ^^

Bien que le niveau de vide total soit discutable dans les versions actuelles de postgresql, le fait de procéder à une "analyse par le vide" ou à un "réindexation" après certaines actions massives peut améliorer les performances ou nettoyer l'utilisation du disque. Ceci est spécifique à PostgreSQL, et doit être nettoyé pour que les autres bases de données puissent fonctionner correctement.

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)

Malheureusement, le proxy de connexion fourni par django ne permet pas d'accéder à set_isolation_level.

Remarque Si vous utilisez Django avec South pour effectuer une migration, vous pouvez utiliser le code suivant pour exécuter un ANALYSE VACUUM .

def forwards(self, orm):

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

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

Je ne connais pas psycopg2 et PostgreSQL, mais uniquement apsw et SQLite. Je ne peux donc pas donner de "psycopg2". aide.

Mais il me semble que PostgreSQL pourrait fonctionner de la même façon que SQLite, il a deux modes de fonctionnement:

  • En dehors d'un bloc de transaction: équivaut sémantiquement à un bloc de transaction pour chaque opération SQL
  • À l'intérieur d'un bloc de transaction, marqué par "BEGIN TRANSACTION". et terminé par "END TRANSACTION"

Dans ce cas, le problème pourrait être lié à la couche d'accès psycopg2. Lorsqu'il fonctionne normalement de manière à ce que les transactions soient insérées implicitement jusqu'à la validation, il pourrait ne pas y avoir de "méthode standard". faire le vide.

Bien sûr, il est possible que "psycopg2" a son " vide " spécial méthode, ou un mode de fonctionnement spécial, dans lequel aucune transaction implicite n'est démarrée.

Lorsque de telles possibilités n'existent pas, il ne reste qu'une seule option (sans changer la couche d'accès ;-)):

La plupart des bases de données ont un programme shell pour accéder à la base de données. Le programme pourrait exécuter ce programme shell avec un tuyau (en entrant la commande vacuum dans le shell), utilisant ainsi le programme shell pour créer le vide. Puisque le vide est une opération lente en tant que telle, le démarrage d'un programme externe sera négligeable. Bien entendu, le programme actuel devrait engager tous les travaux non validés avant, sinon il pourrait y avoir une impasse: l’aspirateur doit attendre la fin de votre dernière transaction.

Ne le faites pas - vous n’avez pas besoin de VACUUM FULL. En fait, si vous utilisez une version quelque peu récente de Postgres (disons & 8.1), vous n'avez même pas besoin d'exécuter manuellement VACUUM.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top