Какие нюансы при добавлении новой колонки в таблицу
Что проверяют
Знаете ли вы, что ALTER TABLE ... ADD COLUMN на живой таблице может положить сервис, и умеете ли выкатывать схему без простоя. Следом обычно спрашивают, как сделать новую колонку NOT NULL на таблице в десятки миллионов строк.
Как отвечать
Разберите по шагам на примере PostgreSQL и миграций Alembic или Django:
- блокировка: любой
ADD COLUMNберётACCESS EXCLUSIVE. Сама операция быстрая, но если перед ней висит долгая транзакция, миграция ждёт, а за ней встают все запросы к таблице. Поэтому в миграции ставятSET lock_timeout = '5s'и повторяют попытку; - значение по умолчанию: начиная с PostgreSQL 11 колонка с константным
DEFAULTдобавляется без перезаписи таблицы, меняются только метаданные. Изменчивый дефолт вродеclock_timestamp()илиgen_random_uuid()перепишет каждую строку; - NOT NULL: на непустую таблицу без дефолта сразу не добавится. Безопасный путь: колонка nullable, бэкофилл пачками по несколько тысяч строк, затем
CHECK (col IS NOT NULL) NOT VALID,VALIDATE CONSTRAINTиSET NOT NULL, который с PostgreSQL 12 опирается на проверенное ограничение и не сканирует таблицу; - индекс: только
CREATE INDEX CONCURRENTLY, а он не работает внутри транзакции. В Alembic этоautocommit_block(), в DjangoAddIndexConcurrentlyв миграции сatomic = False; - порядок выкладки: схема расширяется раньше кода. Сначала миграция, потом код, который пишет в колонку, потом бэкофилл и ограничения.
Отдельно про Django: default у поля модели заполняет существующие строки, но в самой базе дефолт не остаётся. Если он нужен на уровне базы, в Django 5 для этого есть db_default.
Где спотыкаются
Заполняют колонку одним UPDATE на всю таблицу. Это гигантская транзакция, раздувание таблицы и долгие блокировки строк.
Не думают об очереди блокировок: миграция без lock_timeout, вставшая за одной долгой аналитической выборкой, останавливает прод на минуты.
Смотрят только на базу и забывают про код: старые инстансы приложения во время деплоя, SELECT * с разбором по позиции и сериализаторы ломаются раньше, чем сама миграция.