Самый эффективный способ добавить последовательный столбец в огромную таблицу

10

Какой самый быстрый способ добавить столбец BIGSERIAL в огромную таблицу (~ 3 млрд строк, ~ 174 Гб)?

РЕДАКТИРОВАТЬ:

  • Я хочу, чтобы столбец увеличивал значения для существующих строк ( NOT NULL).
  • Я не установил fillfactor (который выглядит как плохое решение в ретроспективе).
  • У меня нет проблем с дисковым пространством, просто хочу, чтобы оно было максимально быстрым.
Ти Дуонг Нгуен
источник

Ответы:

12

Что случилось с:

ALTER TABLE foo ADD column bar bigserial;

Будут заполнены уникальными значениями автоматически (начиная с 1).

Если вам нужен номер для каждой существующей строки, каждая строка в таблице должна быть обновлена . Или нет?

Таблица будет увеличена вдвое по размеру, если она не сможет повторно использовать мертвые кортежи или свободное пространство на страницах данных. Производительность этой операции может значительно выиграть от FILLFACTORтого, что на столе меньше 100 или просто случайные мертвые кортежи. В противном случае вы можете захотеть запустить VACUUM FULL ANALYZEвпоследствии, чтобы восстановить дисковое пространство. Это не будет быстро, хотя.

pgstattuple
Вы можете быть заинтересованы в этом расширении. Это поможет вам собрать статистику по вашим таблицам. Чтобы узнать о мертвых кортежах и свободном пространстве:

Установите расширение один раз для данных:

CREATE EXTENSION pgstattuple;

Вызов:

SELECT * FROM pgstattuple('tbl');

альтернатива

Если вы можете позволить себе создать новую таблицу, которая будет разбиваться в зависимости от представлений, внешних ключей, ...

Создайте пустую копию старой таблицы:

CREATE new_tbl AS
SELECT *
FROM   old_tbl
LIMIT  0;

Добавьте колонку bigserial:

ALTER new_tbl ADD column bar bigserial;

ВСТАВЬТЕ данные из старой таблицы, автоматически заполнив bigserial:

INSERT INTO new_tbl
SELECT *    --  new column will be filled with default
FROM   old_tbl
ORDER  BY something; -- or don't order if you don't care: faster

Новый столбец bigserial отсутствует в SELECT INSERT и будет автоматически заполнен значением по умолчанию . Вы можете прописать все столбцы и добавить nextval()в SELECTсписок тот же эффект.

Убедитесь, что вы получили все свои данные в новой таблице.
Добавить индексы, ограничения, триггеры была в старом столе в настоящее время .

DROP TABLE old_tbl;
ALTER TABLE new_tbl RENAME TO old_tbl;

Может быть, немного быстрее в целом. Это оставляет вас с ванильным столом (и индексами) без какого-либо раздувания.

Вам нужно свободное дисковое пространство - размером с старый стол, в зависимости от состояния стола - в качестве комнаты для маневра. Но вам может понадобиться столько же с первым простым методом из-за раздувания таблицы. Опять же, детали зависят от состояния вашей таблицы.

Эрвин Брандштеттер
источник
3
Оберните альтернативу в одну транзакцию, это будет намного быстрее. Это позволит избежать дополнительных fsyncс
Фрэнк Хейкенс