Postgresql как запустить что то вне транзакции
Перейти к содержимому

Postgresql как запустить что то вне транзакции

  • автор:

Postgresql как запустить что то вне транзакции

Транзакции — это фундаментальное понятие во всех СУБД. Суть транзакции в том, что она объединяет последовательность действий в одну операцию «всё или ничего». Промежуточные состояния внутри последовательности не видны другим транзакциям, и если что-то помешает успешно завершить транзакцию, ни один из результатов этих действий не сохранится в базе данных.

Например, рассмотрим базу данных банка, в которой содержится информация о счетах клиентов, а также общие суммы по отделениям банка. Предположим, что мы хотим перевести 100 долларов со счёта Алисы на счёт Боба. Простоты ради, соответствующие SQL-команды можно записать так:

Точное содержание команд здесь не важно, важно лишь то, что для выполнения этой довольно простой операции потребовалось несколько отдельных действий. При этом с точки зрения банка необходимо, чтобы все эти действия выполнились вместе, либо не выполнились совсем. Если Боб получит 100 долларов, но они не будут списаны со счёта Алисы, объяснить это сбоем системы определённо не удастся. И наоборот, Алиса вряд ли будет довольна, если она переведёт деньги, а до Боба они не дойдут. Нам нужна гарантия, что если что-то помешает выполнить операцию до конца, ни одно из действий не оставит следа в базе данных. И мы получаем эту гарантию, объединяя действия в одну транзакцию. Говорят, что транзакция атомарна: с точки зрения других транзакций она либо выполняется и фиксируется полностью, либо не фиксируется совсем.

Нам также нужна гарантия, что после завершения и подтверждения транзакции системой баз данных, её результаты в самом деле сохраняются и не будут потеряны, даже если вскоре произойдёт авария. Например, если мы списали сумму и выдали её Бобу, мы должны исключить возможность того, что сумма на его счёте восстановится, как только он выйдет за двери банка. Транзакционная база данных гарантирует, что все изменения записываются в постоянное хранилище (например, на диск) до того, как транзакция будет считаться завершённой.

Другая важная характеристика транзакционных баз данных тесно связана с атомарностью изменений: когда одновременно выполняется множество транзакций, каждая из них не видит незавершённые изменения, произведённые другими. Например, если одна транзакция подсчитывает баланс по отделениям, будет неправильно, если она посчитает расход в отделении Алисы, но не учтёт приход в отделении Боба, или наоборот. Поэтому свойство транзакций «всё или ничего» должно определять не только, как изменения сохраняются в базе данных, но и как они видны в процессе работы. Изменения, производимые открытой транзакцией, невидимы для других транзакций, пока она не будет завершена, а затем они становятся видны все сразу.

В PostgreSQL транзакция определяется набором SQL-команд, окружённым командами BEGIN и COMMIT . Таким образом, наша банковская транзакция должна была бы выглядеть так:

Если в процессе выполнения транзакции мы решим, что не хотим фиксировать её изменения (например, потому что оказалось, что баланс Алисы стал отрицательным), мы можем выполнить команду ROLLBACK вместо COMMIT , и все наши изменения будут отменены.

PostgreSQL на самом деле отрабатывает каждый SQL-оператор как транзакцию. Если вы не вставите команду BEGIN , то каждый отдельный оператор будет неявно окружён командами BEGIN и COMMIT (в случае успешного завершения). Группу операторов, окружённых командами BEGIN и COMMIT иногда называют блоком транзакции.

Примечание

Некоторые клиентские библиотеки добавляют команды BEGIN и COMMIT автоматически и неявно создают за вас блоки транзакций. Подробнее об этом вы можете узнать в документации интересующего вас интерфейса.

Операторами в транзакции можно также управлять на более детальном уровне, используя точки сохранения. Точки сохранения позволяют выборочно отменять некоторые части транзакции и фиксировать все остальные. Определив точку сохранения с помощью SAVEPOINT , при необходимости вы можете вернуться к ней с помощью команды ROLLBACK TO . Все изменения в базе данных, произошедшие после точки сохранения и до момента отката, отменяются, но изменения, произведённые ранее, сохраняются.

Когда вы возвращаетесь к точке сохранения, она продолжает существовать, так что вы можете откатываться к ней несколько раз. С другой стороны, если вы уверены, что вам не придётся откатываться к определённой точке сохранения, её можно удалить, чтобы система высвободила ресурсы. Помните, что при удалении или откате к точке сохранения все точки сохранения, определённые после неё, автоматически уничтожаются.

Всё это происходит в блоке транзакции, так что в других сеансах работы с базой данных этого не видно. Совершённые действия становятся видны для других сеансов все сразу, только когда вы фиксируете транзакцию, а отменённые действия не видны вообще никогда.

Вернувшись к банковской базе данных, предположим, что мы списываем 100 долларов со счёта Алисы, добавляем их на счёт Боба, и вдруг оказывается, что деньги нужно было перевести Уолли. В данном случае мы можем применить точки сохранения:

Этот пример, конечно, несколько надуман, но он показывает, как можно управлять выполнением команд в блоке транзакций, используя точки сохранения. Более того, ROLLBACK TO — это единственный способ вернуть контроль над блоком транзакций, оказавшимся в прерванном состоянии из-за ошибки системы, не считая возможности полностью отменить её и начать снова.

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

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

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

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

6 ответов

После дополнительных поисков я обнаружил свойство изоляции_level объекта соединения psycopg2. Оказывается, изменение этого значения на 0 выведет вас из блока транзакции. Изменение вакуумного метода вышеупомянутого класса к следующему решает это. Обратите внимание, что я также установил уровень изоляции на прежний уровень (кажется, 1 по умолчанию).

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

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

Эта команда печатает список с сообщением журнала запросов, таких как Vacuum и Analyze:

Это может быть полезно для администраторов баз данных ^^

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

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

https://amdy.su/wp-admin/options-general.php?page=ad-inserter.php#tab-8

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

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

  • Вне блока транзакции: это семантически эквивалентно иметь блок транзакции вокруг каждой отдельной операции SQL
  • Внутри блока транзакции, который помечен как «НАЧАЛО ТРАНЗАКЦИИ» и завершен как «КОНЕЦ ТРАНЗАКЦИИ»

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

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

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

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

Обратите внимание, что если вы используете Django с South для выполнения миграции, вы можете использовать следующий код для выполнения VACUUM ANALYZE .

Не делай этого — ВАКУУМ НЕ ТРЕБУЕТСЯ. На самом деле, если вы используете более позднюю версию Postgres (скажем,> 8.1), вам даже не нужно запускать простой VACUUM вручную.

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

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

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

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

задан 19 июн ’09, 08:06

@nosklo, Хорошее предложение, но согласно документам Postgres это то же самое, что и COMMIT. — Wayne Koorts

Вы случайно не используете SQLAlchemy? У меня возникла похожая проблема, потому что установка autocommit = True в SqlAlchemy не на самом деле отключить транзакции. С использованием set_isolation_level — это обходной путь, который обращается к внутренним методам соединения psycopg2. — Michael Aquilina

@MichaelAquilina Я считаю, что в то время (это было 6 лет назад) это было частью проекта, который не использовал ORM. — Wayne Koorts

6 ответы

После дополнительных поисков я обнаружил свойство isolated_level объекта подключения psycopg2. Оказывается, изменив это на 0 выведет вас из блока транзакции. Ее решает изменение метода вакуумирования вышеуказанного класса на следующий. Обратите внимание, что я также установил уровень изоляции обратно на тот, который был ранее на всякий случай (кажется, 1 по умолчанию).

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

ответ дан 11 мар ’20, в 21:03

Или, избегая магических чисел: self.conn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT) — Нуно Андре

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

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

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

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

Это может быть полезно администраторам баз данных ^^

Вам нужно запустить cursor.execute (‘VACUUM FULL VERBOSE’), чтобы действительно получить что-то в этом свойстве. — Влакс

Обратите внимание: если вы используете Django с South для выполнения миграции, вы можете использовать следующий код для выполнения VACUUM ANALYZE .

Я не знаю psycopg2 и PostgreSQL, но знаю только apsw и SQLite, поэтому думаю, что не могу помочь вам с «psycopg2».

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

  • Вне блока транзакции: семантически эквивалентен блоку транзакции вокруг каждой отдельной операции SQL.
  • Внутри блока транзакции, который отмечен надписью «НАЧАТЬ ТРАНЗАКЦИЮ» и завершен надписью «КОНЕЦ ТРАНЗАКЦИИ».

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

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

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

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

Thread: SELECT FOR UPDATE без транзакции

> Привет
> Вы в принципе не можете сделать select вне транзакции. Если вы делаете
> запрос вне транзакции — этот запрос будет обёрнут в отдельную транзакцию
> автоматически.

ну я примерно так и думал, просто решил уточнить 🙂

> Не представляю зачем в вашем примере мог быть нужен s1 вообще — но да,
> так брать блокировку возможно.

Я немного неудачно пример записал.

в моём случае второй запрос еще должен сделать insert в t2 на самом
деле.

то есть полеый алгоритм такой:

1. ставим лок на запись t1
2. записываем новую запись t2
3. аггрегатором вычисляем по t2 значение
4. модифицируем запись в t1 на которую поставили лок

(условно говоря первая таблица — таблица со значениями неких
счетчиков, вторая таблица — таблица с логом операций над счетчиками)

В целом у меня подобная система работает без блокировок, но на одном
процессе (конкурентность отстуствует). Сейчас хочу запустить второй
параллельный процесс. Он будет очень редко пересекаться по ID записей,
однако поскольку пересечения возможны — задумался над локами.

’ GPG key: 4096R/08EEA756 2014-08-30
`- 71ED ACFC 6801 0DD9 1AD1 9B86 8D1F 969A 08EE A756

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *