Безопасно ли отменить запрос PostgreSQL ALTER TABLE, ожидающий блокировки?

10

Мы начали ALTER TABLEзапрос несколько часов назад и только недавно поняли (через pg_stat_activity), что он ожидает блокировки. Мы обнаружили другой запрос, который удерживает блокировку таблицы, которую мы хотим изменить, и не отпускает ее.

Наш запрос является «простым» запросом (изменяющим тип данных столбца), но он выполняется для массивной таблицы.

Вместо того, чтобы убивать процесс, который держит блокировку, мы решили, что лучше убить ALTER TABLE.

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

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

Это правда? Безопасно ли нам сразу отменить наш ALTER TABLEзапрос? Или возможно, что запрос уже изменил что-то, и его отмена оставила бы нашу базу данных в каком-то наполовину состоянии?

PS: план состоит в том, чтобы отменить его с помощью SELECT pg_cancel_backend(pid);. Если это плохая идея, пожалуйста, дайте мне знать.

JMTyler
источник
1
Должно быть хорошо, чтобы отменить ALTER TABLE. PostgreSQL имеет транзакционный DDL, и вы должны остаться в том же состоянии, как если бы вы вообще не запускали ALTER TABLE.
Джош Купершмидт
Итак, когда вы говорите, что PostgreSQL имеет DDL транзакции, означает ли это, что любой запрос на изменение схемы по сути выполняется внутри транзакции?
JMTyler
1
В вашем случае ALTER TABLE «по сути запускается внутри транзакции», поскольку вы сказали «Мы не включили ALTER TABLE в транзакцию». Хотя, если вы хотите, вы можете написать НАЧАТЬ; ALTER TABLE foo ...; Панель ALTER TABLE ...; так далее. ; COMMIT; - это реальная особенность PostgreSQL, имеющая транзакционный DDL. Но для вашей непосредственной ситуации, да, ALTER TABLE сам по себе может быть безопасно отменен и будет отменен, как если бы это никогда не происходило.
Джош Купершмидт
Большое спасибо за ваши быстрые ответы! Это очень хорошая информация. Не могли бы вы опубликовать его как ответ, чтобы я мог отметить его как принятый?
JMTyler

Ответы:

13

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

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

Безопасно ли нам полностью отменить наш запрос ALTER TABLE? Или возможно, что запрос уже изменил что-то, и его отмена оставила бы нашу базу данных в каком-то наполовину состоянии?

Отмена запросов (или, что то же самое, откат транзакции) в PostgreSQL не имеет каких-либо рисков повреждения базы данных, которые вы могли бы напугать в некоторых других базах данных (например, ужасающее предупреждение внизу этой страницы). Вот почему пользователи, не являющиеся суперпользователями, в последних версиях могут свободно использовать pg_cancel_backend()и pg_terminate_backend()уничтожать свои собственные запросы, выполняемые в других бэкэндах - их можно безопасно использовать, не беспокоясь о повреждении базы данных. В конце концов, PostgreSQL должен быть подготовлен к тому, чтобы справляться с любыми процессами, такими как SIGKILL от OOM killer, выключение сервера и т. Д. Вот для чего нужен журнал 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 и (в случае успеха) обертку вокруг него. Группу операторов, окруженную 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. Если у вас есть проблемы с синхронизацией, то вы небезопасны для всего .
Крейг Рингер