Pull to refresh

Comments 3

Нельзя говорить, что «ACCESS EXCLUSIVE — это быстро» без указания на то, что чтобы взять ACCESS EXCLUSIVE не должно быть абсолютно никого, кто с этой таблицей работает. И нет, вакуумов для этого списка недостаточно. Потому что когда команда хочет взять блокировку, то проверяется, нет ли любой другой транзакции с конфликтующей блокировкой (а с ACCESS EXCLUSIVE конфликтуют абсолютно все). Если есть такая (хоть простой select когда-то давно в начале транзакции) — то мы ставим ACCESS EXCLUSIVE в ожидание блокировки и ждём конфликтующие транзакции. При этом, все последующие обращения к этой таблице не будут выполняться, а будут ждать уже наш ACCESS EXCLUSIVE. Как итог — прод лежит до тех пор пока не снимут alter table или завершатся транзакции, мешавшие взять ACCESS EXCLUSIVE и затем завершится транзакция с этим alter table.

Всё что хочет взять ACCESS EXCLUSIVE на проде вносится так:
begin;
set local statement_timeout to '100ms';
alter table ...
commit;

Тогда если за указанный таймаут мы не выполнили команду (и без разницы, лок не смогли взять или ошиблись в самой миграции и она, например, делает rewrite table) — миграция отменяется. И можно спокойно посмотреть, а кто нам там мешает, затем пробовать внести ещё раз. Величина таймаута подбирается под проект. Чем короче транзакции — тем соответственно проще.

Если мы говорим, например, об операции DROP INDEX CONCURRENTLY, то она имеет блокировку SHARE UPDATE EXCLUSIVE — точно такая же блокировка имеется и у вакуума. В результате чего, если запустить такое удаление индексов и вакуум будет в процессе, то возникнет конфликт интересов.

И что? DROP INDEX CONCURRENTLY потому и CONCURRENTLY что не будет мешать обычной работе. Подождёт пока закончит вакуум и выполнится. Если это регулярный автовакуум — то тот сам отменится, если wraparound — то подождём мы.

Наличие CONCURRENTLY является обязательным условием, так как это позволяет нам избежать EXCLUSIVE LOCK на таблицу.

CREATE INDEX не использует EXCLUSIVE LOCK. Только SHARE. Что означает блокировку записи, но не чтения. Обычно тоже не интересно, второй seqscan всей таблицы от concurrently обычно предпочтительнее и потому всегда CREATE INDEX CONCURRENTLY. Но это не эксклюзивная блокировка.

Что про CREATE INDEX CONCURRENTLY надо упомянуть — проверяйте его код возврата. Отменённый/завершившийся ошибкой CREATE INDEX CONCURRENTLY оставит invalid индекс, непригодный для использования в запросах, но (в зависимости от стадии создания) занимающий место и замедляющий запись.

Не понял, про какое место  имеется в виду:

что «ACCESS EXCLUSIVE — это быстро»

так как единственное место про скорость - это что операция NOT VALID проходит быстро (что собственно взято из доки и перефразировано But if the NOT VALID option is used, this potentially-lengthy scan is skipped.)

И что? DROP INDEX CONCURRENTLY потому и CONCURRENTLY что не будет мешать обычной работе. Подождёт пока закончит вакуум и выполнится. 

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

так как единственное место про скорость — это что операция NOT VALID проходит быстро

Именно про это место. Добавление NOT VALID constraint быстрое настолько насколько быстро получится взять ACCESS EXCLUSIVE. Если не получится быстро взять — будут приключения.
Sign up to leave a comment.