Миграция `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, если они последовательные). Как только вы закончите, переключите таблицы и удалите старую.

Это, очевидно, требует вдвое больше места, но будет работать без простоев.

Другие вопросы по тегам