Миграция `int` в`bigint` в PostgresSQL без простоев?
У меня есть база данных, которая столкнется с проблемой исчерпания целых чисел, с которой Basecamp классно столкнулся еще в ноябре. У меня есть несколько месяцев, чтобы понять, что делать.
Существует ли не требующее простоя, упреждающее решение для миграции этого типа столбца? Если так, то, что это? Если нет, то нужно ли просто съесть время простоя и перенести колонку, когда я смогу?
Достаточно ли этой статьи, если у меня есть несколько дней / недель, чтобы выполнить миграцию сейчас, прежде чем я буду вынужден сделать это, когда у меня закончатся идентификаторы?
3 ответа
Используйте логическую репликацию.
С логической репликацией вы можете иметь разные типы данных в основном и резервном режиме.
Скопируйте схему с pg_dump -s
измените типы данных на cooy и затем запустите логическую репликацию.
После того, как все данные скопированы, переключитесь на режим ожидания.
Для нулевого времени простоя приложение должно иметь возможность повторно подключиться и повторить попытку, но это всегда является обязательным требованием в таком случае.
Для этого вам понадобится PostgreSQL v10 или выше, и ваша база данных не должна изменять схему, поскольку DDL не реплицируется.
Другое решение для баз данных до v10, где все транзакции короткие:
Добавить
bigint
столбец к таблице.Создать
BEFORE
триггер, который устанавливает новый столбец всякий раз, когда строка добавляется или обновляется.Запустите серию обновлений, которые устанавливают новый столбец из старого, где он
IS NULL
, Держите эти партии короткими, чтобы не блокировать долго и не блокировать много. Убедитесь, что эти транзакции выполняются сsession_replication_role = replica
поэтому они не запускают триггеры.После того как все строки uodated, создайте уникальный индекс
CONCURRENTLY
на новом столбце.Добавить уникальное ограничение
USING
индекс, который вы только что создали. Это будет быстро.Выполните переключение:
BEGIN; ALTER TABLE ... DROP oldcol; ALTER TABLE ... ALTER newcol RENAME TO oldcol; COMMIT;
Это будет быстро.
Ваша новая колонка не имеет NOT NULL
задавать. Это не может быть сделано без длинной инвазивной блокировки. Но вы можете добавить ограничение ckeck IS NOT NULL
и создать его NOT VALID
, Это достаточно хорошо, и вы можете позже проверить это без сбоев.
Если есть ограничения внешнего ключа, все становится немного сложнее. Вы должны отбросить их и создать NOT VALID
внешние ключи к новому столбцу.
Создайте копию старой таблицы, но с измененным полем ID. Затем создайте триггер на старой таблице, который вставляет новые данные в обе таблицы. Наконец, скопируйте данные из старой таблицы в новую (было бы неплохо отличать данные перед запуском от пост-триггера, например, по id, если они последовательные). Как только вы закончите, переключите таблицы и удалите старую.
Это, очевидно, требует вдвое больше места, но будет работать без простоев.