PostgreSQL-как запустить вакуум из кода вне блока транзакций?

Я использую Python с psycopg2, и я пытаюсь запустить полный VACUUM после ежедневной операции, которая вставляет несколько тысяч строк. Проблема в том, что когда я пытаюсь запустить VACUUM команда в моем коде я получаю следующую ошибку:

psycopg2.InternalError: VACUUM cannot run inside a transaction block

как запустить это из кода вне блока транзакций?

если это имеет значение, у меня есть простой класс абстракции DB, подмножество которого отображается ниже для контекста (не выполняется, обработка исключений и docstrings опущены, и сделаны корректировки линии охвата):

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)

6 ответов


после дополнительного поиска я обнаружил свойство isolation_level объекта подключения psycopg2. Оказывается, изменив это на 0 выведет вас из блока транзакций. Изменение метода вакуума вышеуказанного класса на следующий решает его. Обратите внимание, что я также установил уровень изоляции на то, что он ранее был на всякий случай (кажется 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)

в этой статье (в конце этой страницы) предоставляет краткое описание объяснение уровней изоляции в этом контексте.


в то время как vacuum full сомнителен в текущих версиях postgresql, принудительный "вакуумный анализ" или "переиндекс" после определенных массовых действий может повысить производительность или очистить использование диска. Это специфично для postgresql и должно быть очищено, чтобы сделать правильную вещь для других баз данных.

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)

к сожалению, прокси-сервер соединения, предоставляемый django, не предоставляет доступ к set_isolation_level.


кроме того, вы также можете получить сообщения, данные вакуумом или анализировать, используя:

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

эта команда печатает список с сообщением журнала запросов, таких как Vacuum и 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"

Это может быть полезно для DBAs ^^


Примечание Если вы используете Django с South для выполнения миграции, вы можете использовать следующий код для выполнения 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()

Я не знаю psycopg2 и PostgreSQL, но только apsw и SQLite, поэтому я думаю, что не могу дать помощь "psycopg2".

но мне кажется, что PostgreSQL может работать так же, как SQLite, он имеет два режима работы:

  • вне блока транзакций: это семантически эквивалентно иметь блок транзакций вокруг каждой операции SQL
  • внутри блока транзакций, который отмечен "начать транзакцию" и заканчивается "конец Сделка"

когда это так, проблема может быть внутри уровня доступа psycopg2. Когда он обычно работает таким образом, что транзакции имплицитно вставляются до фиксации, не может быть "стандартного способа" создать вакуум.

конечно, возможно, что " psycopg2 "имеет свой специальный метод" вакуума " или специальный режим работы, где неявные транзакции не запускаются.

когда таких возможностей не существует, там остается один единственный вариант (без изменения уровня доступа ;-) ):

большинство баз данных имеют оболочку программы для доступа к базе данных. Программа может запустить эту программу оболочки с помощью трубы (ввод команды vacuum в оболочку), таким образом, используя программу оболочки для создания вакуума. Поскольку вакуум является медленной операцией как таковой, запуск внешней программы будет пренебрежимым. Конечно, фактическая программа должна совершить всю незафиксированную работу раньше, иначе может быть тупиковая ситуация-вакуум должен ждать до конца вашей последней транзакции.


Не делайте этого - вам не нужен полный вакуум. На самом деле, если вы запустите несколько последнюю версию Postgres (скажем, > 8.1), вам даже не нужно запускать обычный вакуум вручную.