Чи безпечно скасувати запит PostgreSQL ALTER TABLE, який очікує на замок?


10

Ми розпочали ALTER TABLEзапит години тому і лише нещодавно зрозуміли (через pg_stat_activity), що він чекає на замок. Ми виявили інший запит, який тримає замок на столі, який ми хочемо змінити, і не відпускає його.

Наш запит - це "простий" запит (зміна типу даних стовпця), але він працює на масивній таблиці.

Замість того, щоб вбивати процес, який тримається за замок, ми вирішили скоріше вбити ALTER TABLE.

Ми не завершували ALTER TABLEтранзакцію.

Наскільки я розумію, той факт, що наш запит чекає на замок, означає, що він завжди чекав на замок, і він ніколи нічого не змінював.

Це правда? Чи безпечно для нас прямо скасувати ALTER TABLEзапит? Або можливо, що запит вже щось змінив, і скасування його залишило б нашу базу даних в напівдорожному стані якогось типу?

PS: План полягає в тому, щоб скасувати його за допомогою SELECT pg_cancel_backend(pid);. Якщо це погана ідея, будь ласка, повідомте мене про це.


1
Має бути добре, щоб скасувати ALTER TABLE. PostgreSQL має транзакційний DDL, і ви повинні залишитись у тому ж стані, як якщо б ви взагалі не запускали ALTER TABLE.
Джош Купершмідт

Отже, коли ви говорите, що PostgreSQL має транзакцію DDL, чи означає це, що будь-який запит, що змінює схему, по суті виконується всередині транзакції?
JMTyler

1
У вашому випадку ALTER TABLE "по суті виконується всередині транзакції", оскільки ви сказали: "Ми не обгортали ALTER TABLE в транзакції". Якщо ви хотіли, хоч, ви можете написати BEGIN; ALTER TABLE foo ...; АЛЬТЕР ТАБЛИКА бар ...; тощо; КОМІТЕТ; - ось справжня вбивча особливість PostgreSQL, що має транзакційний DDL. Але для Вашої негайної ситуації, так, ПОДІЛЬНА СТОЛЬКА сама по собі може бути безпечно скасована і буде повернута назад, як ніби ніколи не бувало.
Джош Купершмідт

Дуже дякую за швидкі відповіді! Це дуже гарна інформація. Чи можете ви опублікувати його як відповідь, щоб я міг позначити його як прийняте?
JMTyler

Відповіді:


13

Наскільки я розумію, той факт, що наш запит чекає на замок, означає, що він завжди чекав на замок, і він ніколи нічого не змінював.

Праворуч - якщо ви бачите, що pg_stat_activity.waiting є "істинним" для ALTER TABLE, це майже напевно означає, що він терпляче чекає блокування ACCESS EXCLUSIVE на його цільовій таблиці та його реальної роботи (переписування таблиці, якщо потрібно, зміна каталогів) , відновлення індексів тощо) ще не почалося.

Чи безпечно для нас прямо скасувати запит ALTER TABLE? Або можливо, що запит вже щось змінив, і скасування його залишило б нашу базу даних в напівдорожному стані якогось типу?

Скасування запитів (або, що еквівалентно, повернення транзакції) в PostgreSQL не має жодних небезпек пошкодження бази даних, які, можливо, були опудані в деяких інших базах даних (наприклад, жахливе попередження внизу цієї сторінки). Ось чому в останніх версіях користувачі, які не користуються суперпоширенням, вільні у використанні pg_cancel_backend()та pg_terminate_backend()знищенні власних запитів, що виконуються в інших пакетах - вони безпечні для використання, не замислюючись про пошкодження бази даних. Зрештою, PostgreSQL має бути готовим до вирішення будь-яких процесів, що вбиваються, наприклад, SIGKILL від кілера OOM, відключення сервера тощо. Для цього потрібен журнал WAL .

Можливо, ви також бачили, що в PostgreSQL можна виконувати більшість команд DDL, вкладених у транзакцію (з декількома операторами), наприклад

BEGIN;
ALTER TABLE foo ...;
ALTER TABLE bar ...;
-- more stuff
COMMIT; -- or ROLLBACK; if you've changed your mind

(приголомшливо переконатися, що міграції схеми йдуть або взагалі, або взагалі немає.) Ви сказали, що:

Ми не завершували ALTER TABLEтранзакцію.

Це добре для однієї команди - від документів ,

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

Тож скасування того ALTER TABLE, що через pg_cancel_backend()або Ctrl-C, видане з керуючого запису psql, матиме аналогічний ефект, як якщо б ви це зробили

BEGIN;
ALTER TABLE ... ;
ROLLBACK;

(хоча, як ви сподіваємось побачити, скасування такого дорогого ALTER TABLEможе врятувати базу даних від безлічі шліфування, якщо ви все ROLLBACKодно збираєтесь .)


5

Щоб уточнити правильну та чудову відповідь Джоша:

Чи безпечно для нас прямо скасувати запит ALTER TABLE?

Так.

Це було б безпечно, навіть якби воно було посеред переписування столу .

Якби ви хотіли, ви могли б просто вимкнути весь сервер PostgreSQL, або фактично машину, на якій він працює, перезавантажте його, і все було б добре. DDL в PostgreSQL є транзакційним та безпечним для аварій.

Операції DDL реєструються через WAL, і це гарантовано, що вони можуть бути відмовлені або завершені після відновлення після аварії або переривання.


3
Лише зауваження про те, що "ви могли просто вимкнути весь сервер PostgreSQL, або насправді машину, на якій він працює, перезапустити його, і все було б добре" - цілком вірно, якщо у вас є надійне обладнання, яке не лежить про fsync , wiki.postgresql.org/wiki/Reliable_Writes
Джош Купершмідт

2
@JoshKupershmidt Звичайно, але це не специфічно для DDL. Якщо у вас є проблеми із синхронізацією, ви не безпечні для всього .
Крейг Рінгер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.