Комментарии 12
Здесь есть существенное допущение, что первичный ключ некластерный, что позволило заранее подготовить индекс с новым типом. Не рассматривался вариант с новой таблицей, куда все скопировано и потом переключение? Все равно после манипуляций с колонками таблицу наверное надо "выравнивать"(появились пустые байты, новая колонка где то сбоку записалась). Подошло бы и под кластерный ключ.
В случае же сегментного UPDATE, autovacuum может успевать оперативно высвобождать место, если процесс сильно растянут во времени.
Один маааленький нюанс не учтён в этом сценарии — всё это не будет работать пока есть хотя бы один VIEW который ссылается на одно из модифицируемых полей (прямо или косвенно), то есть эти VIEW нужно сначала удалить (перед модификацией) а потом пересоздать.
Нужно также не забыть про ограничения доступа и прочие мелочи, но если всё что нам нужно это изменить INT на BIGINT, то достаточно будет этого набора и банального ALTER TABLE tab ALTER COLUMN id TYPE BIGINT
в промежутке между сохранением зависимостей и восстановлением (всё онлайн и в транзакции) — никаких триггеров, дропов, промежуточных полей, переименований и прочих бубнов (кроме, разумеется, пересоздания VIEWs которые и делает упомянутая тулза).
Может GRANT и RULE и редко используются, но вот VIEWs это очень распостранённая вещь, редкая база (кроме разве что вордпрессовских и подобных) без них обходится, уж зело удобно это для массы вещей.
Но если у вас нет VIEW — то зачем вообще городить огород? Почему просто не сделать ALTER COLUMN id BIGINT
? Ничего больше не нужно — всё автоматом сконвертируется, индексы менять не надо, вообще ничего делать не надо.
Просто ALTER COLUMN SET TYPE повесит блокировку на таблицу и начнет ее грустно переписывать. От версии к версии необходимость full rewrite все снижается, но если varchar(n) / text поддержали еще в 9.1, то timestamp / timestamptz — только в v12.
Пример из практики, как раз в тему статьи. У нас в одной из версий системы (речь о oracle, но суть та же) pk/fk были number. В следующей версии сделали их number(9,0). Все приложения со статической типизацией полей стали валиться с ошибками несоответствия типов. Поправили типы полей. Однако хочется и обратной совместимости — чтобы приложения могли работать и с предыдущей версией БД. Если бы не было view пришлось бы поддерживать 2 версии, а так просто во VIEW поправили select pk… на select cast(pk as number(9,0)) as pk…
И да, самое сложное не в самой базе, а в приложения ее использующих — далеко не все из приложений стерпят молча замену int на bigint
BIGINT/BIGSERIAL наше всё. Маленькие числовые типы в primary key — антипаттерн. Потому что на него слишком много всего завязано.
Вообще-то нередко бывают случаи когда число строк в таблице гарантированно вписывается не только в 32 бита а даже в 16 или 8 — если это таблица определений а-ля список типов/enum/etc и ещё чего-то заведомо малочисленного. Плюс, если на них ссылаются где-то из реально больших таблиц то это может сэкономить кучу места и повысить производительность (потому что по FK строят индексы).
BIGINT/BIGSERIAL наше всё
а почему не uuid?
Автоматизация по смене типа данных есть в скрипте https://github.com/comagic/transparent_alter_type
Работает в фоне и незаметно для приложения, как и pg_repack.
DBA: когда почти закончился serial