A maneira mais eficiente de adicionar uma coluna serial a uma tabela enorme


10

Qual é a maneira mais rápida de adicionar uma coluna BIGSERIAL a uma tabela enorme (~ 3 bilhões de linhas, ~ 174 GB)?

EDITAR:

  • Eu quero que a coluna seja incrementada em valores para as linhas existentes ( NOT NULL).
  • Não defini um fator de preenchimento (que parece uma péssima decisão em retrospecto).
  • Não tenho problemas com espaço em disco, só quero que seja o mais rápido possível.

Respostas:


12

O que há de errado com:

ALTER TABLE foo ADD column bar bigserial;

Será preenchido com valores exclusivos automaticamente (começando com 1).

Se você deseja um número para cada linha existente, todas as linhas da tabela precisam ser atualizadas . Ou não?

A tabela ficará com o dobro do tamanho se não puder reutilizar tuplas mortas ou espaço livre nas páginas de dados. O desempenho da operação pode se beneficiar muito com FILLFACTORmenos de 100 ou apenas tuplas mortas aleatórias espalhadas sobre a mesa. Caso contrário, você poderá executar VACUUM FULL ANALYZEposteriormente para recuperar o espaço em disco. Isso não será rápido, no entanto.

pgstattuple
Você pode estar interessado nesta extensão. Ajuda a reunir estatísticas em suas tabelas. Para descobrir sobre tuplas mortas e espaço livre:

Instale a extensão uma vez por banco de dados:

CREATE EXTENSION pgstattuple;

Ligar:

SELECT * FROM pgstattuple('tbl');

Alternativa

Se você puder se dar ao luxo de criar uma nova tabela, que quebraria dependendo de visualizações, chaves estrangeiras, ...

Crie uma cópia vazia da tabela antiga:

CREATE new_tbl AS
SELECT *
FROM   old_tbl
LIMIT  0;

Adicione a coluna bigserial:

ALTER new_tbl ADD column bar bigserial;

INSERIR dados da tabela antiga, preenchendo automaticamente o 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

A nova coluna bigserial está ausente no SELECT do INSERT e será preenchida com seu valor padrão automaticamente . Você pode especificar todas as colunas e adicionar nextval()à SELECTlista com o mesmo efeito.

Certifique-se de ter todos os seus dados na nova tabela.
Adicione índices, restrições, gatilhos que você tinha na tabela antiga agora .

DROP TABLE old_tbl;
ALTER TABLE new_tbl RENAME TO old_tbl;

No geral, pode ser um pouco mais rápido. Isso deixa você com uma tabela de baunilha (e índices) sem inchaço.

Você precisa de espaço livre em disco - em torno do tamanho da tabela antiga, dependendo do estado da tabela - como sala de manobra. Mas você pode precisar tanto do primeiro método simples por causa do inchaço da tabela. Novamente, os detalhes dependem do estado da sua tabela.


3
Embrulhe a alternativa em uma única transação, que será muito mais rápida. Ele vai evitar adicionais fsyncs
Frank Heikens
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.