Estoy usando Python con psycopg2 y estoy tratando de ejecutar un completo VACUUM después de la operación diaria, que introduce varios miles de filas. El problema es que cuando intento ejecutar el VACUUM comando dentro de mi código me sale el siguiente error:

psycopg2.InternalError: VACUUM cannot run inside a transaction block

¿Cómo puedo ejecutar desde el código fuera de un bloque de transacciones?

Si se hace una diferencia, tengo una simple DB abstracción de la clase, un subconjunto de los cuales se muestran a continuación para el contexto (no ejecutables, control de excepciones y docstrings omitido, y la línea que abarca los ajustes realizados):

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)
  • intente enviar FINAL de la TRANSACCIÓN?
  • Buena sugerencia, pero de acuerdo a la Postgres docs que es el mismo que COMETER.
  • Está usted usando SQLAlchemy por casualidad? He experimentado un problema similar porque el establecimiento de autocommit=True en SqlAlchemy, en realidad, no apagar las transacciones. El uso de set_isolation_level es evitar que los accesos de los métodos internos de la psycopg2 conexión.
  • Creo que en ese momento (esto fue hace 6 años ahora) esto fue parte de un proyecto que no estaba usando un ORM.
InformationsquelleAutor Wayne Koorts | 2009-06-19

6 Comentarios

  1. 53

    Después de más búsqueda he descubierto el isolation_level propiedad de la psycopg2 objeto de conexión. Resulta que el cambio de este a 0 se mueve fuera de un bloque de transacciones. Cambiar el método de vacío de la clase anterior a la siguiente soluciona. Tenga en cuenta que yo también establecer el nivel de aislamiento de volver a lo que antes era sólo en caso de que (parece ser 1 por defecto).

    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 artículo (cerca del final de la página) se proporciona una breve explicación de los niveles de aislamiento en este contexto.

    • O, evitando los números de magia: self.conn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
  2. 4

    Además, también puede obtener los mensajes dados por el Vacío o Analizar el uso de:

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

    este comando imprimir una lista con el mensaje de registro de consultas como de Vacío y Analizar:

    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"

    Esto puede ser útil para los Administradores de bases de datos ^^

  3. 4

    Mientras vacío completo es cuestionable en las actuales versiones de postgresql, obligando a un ‘vacío analizar’ o ‘indexar’ después de ciertas acciones masivas puede mejorar el rendimiento, o limpieza de uso de disco. Este es postgresql específicos, y necesita ser limpiado a hacer lo correcto para otras bases de datos.

    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)

    Lamentablemente el proxy de la conexión proporcionada por django no proporciona acceso a set_isolation_level.

  4. 2

    Nota si está utilizando Django con el Sur para realizar una migración puede utilizar el código siguiente para ejecutar 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()
  5. 1

    No sé psycopg2 y PostgreSQL, pero sólo apsw y SQLite, por lo que creo que no puede dar «una psycopg2» ayuda.

    Pero costuras para mí, que PostgreSQL podría funcionar similares como SQLite hace, es que tiene dos modos de operación:

    • Fuera de un bloque de transacciones: Este es semánticamente equivalente a tener un bloque de transacciones alrededor de cada operación de SQL
    • Dentro de un bloque de transacciones, que está marcado por el «BEGIN TRANSACTION» y acaba por «TRANSACCIÓN»

    Cuando este es el caso, el problema podría estar en el interior de la capa de acceso a psycopg2. Cuando se hace normalmente operar de una manera que las transacciones son implícitamente se inserta hasta que un commit se hizo, no puede aplicarse de forma estándar» para hacer un vacío.

    Por supuesto que podría ser posible, que «psycopg2 tiene sus» especiales «vacío» método, o un especial modo de operación, donde no hay transacciones implícitas se han iniciado.

    Cuando no hay tal posibilidad existe, no queda una sola opción (sin cambiar la capa de acceso 😉 ):

    La mayoría de las bases de datos tienen una concha programa para acceder a la base de datos. El programa puede ejecutar este programa de shell con una tubería (entrar en el vacío de comandos en el shell), así que usando el shell programa para hacer el vacío. Desde que el vacío es una operación lenta, como tal, el inicio de un programa externo será despreciable. Por supuesto, el programa debe cometer todos los uncommited trabajo antes, de lo contrario podría haber un punto muerto en el que la situación de la aspiradora debe esperar hasta el final de su última transacción.

    • Gracias por tu detallada respuesta. Resulta que la solución era hacer con «los niveles de aislamiento», véase mi respuesta a continuación.
  6. -3

    No hacerlo, no hay necesidad de VACÍO COMPLETO. En realidad, si se ejecuta bien reciente versión de Postgres (digamos > 8.1), usted ni siquiera necesita para ejecutar la llanura de VACÍO manual.

    • Dependiendo de sus patrones de uso, todavía hay veces en que tiene sentido de vacío manualmente en mi humilde opinión.
    • Hay, pero no hay muchos más. Y definitivamente no debe de VACÍO COMPLETO.
    • Yo estoy en PostGres y con algunas tablas grandes. Todos los libros (hablando de un 8.* o 9.* la perspectiva) hablar acerca de la ejecución de VACÍO ANALIZAR manualmente después de un montón de actualizaciones, o automáticamente con un demonio.
    • «después de la operación diaria, que introduce varios miles de filas», utilidades, como esto sin duda se debe al VACÍO cuando han terminado.
    • Koch: hay una diferencia significativa entre VACUUM y VACUUM FULL.
    • Gran diferencia, pero quiero un VACUUM ANALYZE después de un gran lote de actualizaciones, si es accionada por usted o autovacuum. «usted ni siquiera necesita para ejecutar la llanura de VACÍO manual» es un poco engañoso.

Dejar respuesta

Please enter your comment!
Please enter your name here