PostgreSQL-comment exécuter VACUUM à partir du code à l'extérieur du bloc de transaction?

j'utilise Python avec psycopg2 et j'essaye de lancer un full VACUUM après une opération quotidienne qui insère plusieurs milliers de rangées. Le problème est que quand j'essaie de lancer le VACUUM commande dans mon code j'obtiens l'erreur suivante:

psycopg2.InternalError: VACUUM cannot run inside a transaction block

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

si cela fait une différence, j'ai une classe d'abstraction DB simple, dont un sous-ensemble est affiché ci-dessous pour le contexte (non exécutable, gestion des exceptions et docstrings omis et ligne couvrant les ajustements faits):

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)
28
demandé sur Wayne Koorts 2009-06-19 15:26:33

6 réponses

après plus de recherches, j'ai découvert la propriété isolation_level de l'objet connexion psycopg2. Il s'avère que la modification de cette 0 va vous sortir d'un bloc de transaction. Le changement de la méthode de vide de la classe ci-dessus à la classe suivante résout cela. Notez que j'ai aussi définir le niveau d'isolation à ce qu'il était, auparavant, juste au cas où (semble être 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 (près de la fin de cette page) fournit un bref explication des niveaux d'isolement dans ce contexte.

50
répondu Wayne Koorts 2009-06-19 12:18:49

alors que le vide complet est discutable dans les versions actuelles de postgresql, forcer une 'analyse de vide 'ou' reindex ' après certaines actions massives peut améliorer les performances, ou nettoyer l'utilisation du disque. Cela est spécifique à postgresql, et doit être nettoyé pour faire la bonne chose pour les autres bases de données.

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 fournit pas l'accès à set_isolation_level.

4
répondu Chris Dukes 2014-01-15 15:04:30

en outre, vous pouvez également obtenir les messages donnés par le vide ou analyser en utilisant:

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

cette commande affiche une liste avec le message de log des requêtes comme Vacuum et 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"

cela peut être utile pour le DBAs ^^

3
répondu Diego 2011-01-08 21:15:48
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()
2
répondu donturner 2015-09-29 13:43:37

Je ne sais pas psycopg2 et PostgreSQL, mais seulement apsw et SQLite, donc je pense que je ne peux pas donner une aide "psycopg2".

mais il me semble, que PostgreSQL pourrait fonctionner comme SQLite le fait, il a deux modes d'opération:

  • en dehors d'un bloc de transaction: c'est sémantiquement équivalent à avoir un bloc de transaction autour de chaque opération SQL
  • à l'intérieur d'un bloc de transactions, qui est marqué "début du mouvement" et se termine par " FIN TRANSACTION"

Si c'est le cas, le problème pourrait être à l'intérieur de la couche d'accès aux psycopg2. Lorsqu'elle fonctionne normalement de manière à ce que les transactions soient implicitement insérées jusqu'à ce qu'une propagation soit faite, il ne peut y avoir de "méthode standard" pour créer un vide.

bien sûr, il pourrait être possible que "psycopg2" ait sa méthode spéciale "vacuum", ou un mode de fonctionnement spécial, où aucune transaction implicite n'est commencée.

lorsque de telles possibilités n'existent pas, il reste une seule possibilité (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 peut exécuter ce programme shell avec un tube (entrant la commande de vide dans le shell), utilisant ainsi le programme shell pour faire le vide. Comme le vide est une opération lente en tant que telle, le démarrage d'un programme externe sera négligeable. Bien sûr, le programme lui-même devrait engager tous les travaux non engagés avant, sinon il pourrait y avoir un situation de blocage-le vide doit attendre la fin de votre dernière transaction.

1
répondu Juergen 2009-06-19 12:06:45

ne le faites pas - vous n'avez pas besoin de vide complet. En fait, si vous exécutez une version quelque peu récente de Postgres (disons > 8.1), vous n'avez même pas besoin d'exécuter plain VACUUM manuellement.

-3
répondu Milen A. Radev 2009-06-19 12:22:50