Автор Alexey Evlampiev: Your ALTER TABLE Is Fast. The Queue Behind It Is Not
Изменение схемы, которое выполняется шесть миллисекунд, всё ещё может остановить каждое чтение из таблицы на шестнадцать секунд — ущерб наносит ожидание, а не работа.
Вот один и тот же оператор, выполненный дважды для одной и той же таблицы — PostgreSQL 16.14 в локальном контейнере, таблица orders на 100 000 строк, конкурирующая сессия удерживается открытой через pg_sleep. Это иллюстративные числа с одной машины, а не бенчмарк; важен сам ratio, и вы можете воспроизвести его примерно за минуту.
-- Без конкуренции:
ALTER TABLE orders ADD COLUMN note text;
Time: 5.786 ms
-- С одним обычным долго выполняющимся SELECT, открытым на таблице:
ALTER TABLE orders ADD COLUMN note text;
Time: 18065.050 ms (00:18.065)
Второй запуск медленный не потому, что работа тяжелее. Работа идентична и занимает около шести миллисекунд в обоих случаях — добавление столбца без значения по умолчанию не касается ни одной строки, оно лишь редактирует каталог. Восемнадцать секунд тратятся на ожидание блокировки, и пока этот оператор ждёт, он делает кое-что похуже, чем просто медленно работает: он останавливает несвязанных читателей, которые иначе выполнились бы мгновенно.
Именно это стоит усвоить, и это верно независимо от того, какой инструмент миграции вы используете. Время выполнения без конкуренции говорит вам, сколько стоит оператор, когда ничто не стоит у него на пути; оно не предсказывает, во что он обойдётся вашим пользователям. Режим блокировки, время, проведённое в ожидании, и длина окружающей транзакции дополняют эту картину — и только первое число появляется в таймингах ваших миграций.
Безопасное развёртывание с точки зрения блокировок состоит из двух половин. Одна — это проектирование операторов: выбор форм SQL, которые берут более слабые блокировки или откладывают свою дорогостоящую работу до момента, когда блокировка слаба. Другая — это структура программы: выбор того, где проходят границы ваших транзакций, потому что блокировка живёт до конца своей транзакции, а не до конца своего оператора. Эта статья — о первой половине. Она чисто про PostgreSQL и применима независимо от того, с помощью чего вы развёртываете.
Продолжить чтение "ALTER TABLE выполняется быстро. Очередь за ним — нет"