Pregunta

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

psycopg2.InternalError: VACUUM cannot run inside a transaction block

¿Cómo ejecuto esto desde el código fuera de un bloque de transacciones?

Si hace la diferencia, tengo una clase de abstracción de base de datos simple, cuyo subconjunto se muestra a continuación para el contexto (no ejecutable, manejo de excepciones y cadenas de documentos omitidas y ajustes de extensión de línea 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)
¿Fue útil?

Solución

Después de más búsquedas, descubrí la propiedad de nivel de aislamiento del objeto de conexión psycopg2. Resulta que cambiar esto a 0 lo sacará de un bloque de transacciones. Cambiar el método de vacío de la clase anterior a la siguiente lo resuelve. Tenga en cuenta que también configuré el nivel de aislamiento a lo que era anteriormente por si acaso (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 esa página) proporciona una breve explicación del aislamiento niveles en este contexto.

Otros consejos

Además, también puede obtener los mensajes proporcionados por Vacuum o Analyze usando:

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

este comando imprime una lista con el mensaje de registro de consultas como Vacuum and 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"

Esto puede ser útil para los DBA ^^

Si bien el vacío completo es cuestionable en las versiones actuales de postgresql, forzar un 'análisis de vacío' o 'reindexar' después de ciertas acciones masivas puede mejorar el rendimiento o limpiar el uso del disco. Esto es específico de postgresql y debe limpiarse para 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 conexión proporcionado por django no proporciona acceso a set_isolation_level.

Tenga en cuenta que si está usando Django con South para realizar una migración, puede usar el siguiente código para ejecutar un ANÁLISIS DE VACÍO .

def forwards(self, orm):

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

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

No sé psycopg2 y PostgreSQL, pero solo apsw y SQLite, por lo que creo que no puedo dar un "psycopg2". ayuda.

Pero me parece que PostgreSQL podría funcionar de manera similar a como lo hace SQLite, tiene dos modos de operación:

  • Fuera de un bloque de transacción: esto es semánticamente equivalente a tener un bloque de transacción alrededor de cada operación SQL
  • Dentro de un bloque de transacciones, que está marcado por " BEGIN TRANSACTION " y finalizó con " FINALIZAR TRANSACCIÓN "

Cuando este es el caso, el problema podría estar dentro de la capa de acceso psycopg2. Cuando normalmente opera de una manera que las transacciones se insertan implícitamente hasta que se realiza una confirmación, podría no haber una "forma estándar". hacer una aspiradora.

Por supuesto que podría ser posible, que '' psycopg2 '' tiene su especial "vacío" método, o un modo de operación especial, donde no se inician transacciones implícitas.

Cuando no existen tales posibilidades, queda una sola opción (sin cambiar la capa de acceso ;-)):

La mayoría de las bases de datos tienen un programa shell para acceder a la base de datos. El programa podría ejecutar este programa de shell con una tubería (ingresando el comando de vacío en el shell), utilizando así el programa de shell para hacer el vacío. Como el vacío es una operación lenta como tal, el inicio de un programa externo será descuidado. Por supuesto, el programa real debe comprometer todo el trabajo no comprometido antes, de lo contrario podría haber una situación de bloqueo: el vacío debe esperar hasta el final de su última transacción.

No lo hagas, no necesitas VACÍO COMPLETO. En realidad, si ejecuta una versión algo reciente de Postgres (digamos > 8.1), ni siquiera necesita ejecutar VACUUM sin formato manualmente.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top