Use uma coluna serial
Seu plano é adicionar um índice desnecessariamente grande para 40 milhões (!) de linhas. E você nem tem certeza de que será único. Eu aconselharia fortemente contra essa via de ação. Adicione um
serial
coluna em vez disso e pronto:ALTER TABLE tbl ADD COLUMN tbl_id serial PRIMARY KEY;
Isso é tudo que você precisa fazer. O resto acontece automaticamente. Mais no manual ou nestas respostas intimamente relacionadas:
O incremento automático da chave primária do PostgreSQL falha em C++
Função SQL de incremento automático
Adicionando um
serial
coluna é uma operação única, mas cara. A tabela inteira deve ser reescrita, bloqueando as atualizações durante a operação. Melhor feito sem carga simultânea em horas de folga. Cito o manual aqui
:Como isso efetivamente reescreve toda a tabela, você também pode criar uma nova tabela com uma coluna serial pk, inserir todas as linhas da tabela antiga, deixando o serial preencher com valores padrão de sua sequência, descartar o antigo e renomear o novo. Mais nestas respostas intimamente relacionadas:
Atualizando linhas do banco de dados sem bloquear a tabela no PostgreSQL 9.2
Adicionar nova coluna sem tabela bloquear?
Certifique-se de que todas as suas instruções INSERT tenham uma lista de destino, então uma coluna adicional não poderá confundi-las:
INSERT INTO tbl (col1, col2, ...) VALUES ...
Não:
INSERT INTO tbl VALUES ...
Um
série
é implementado com um inteiro
coluna (4 bytes).Uma restrição de chave primária é implementada com um índice exclusivo e um
NOT NULL
restrição nas colunas envolvidas.O conteúdo de um índice é armazenado como tabelas. O armazenamento físico adicional é necessário separadamente. Mais sobre armazenamento físico nesta resposta relacionada:
Calculando e economizando espaço no PostgreSQL
Seu índice incluiria 2 carimbos de data/hora (2 x 8 bytes) mais um nome de arquivo longo incl. path (~ 50 bytes?) Isso tornaria o índice em torno de 2,5 GB maior (40M x 60 .. algo bytes) e todas as operações mais lentas.
Lidando com duplicatas
Como lidar com "importar duplicatas" depende de como você está importando dados e como "duplicado" é definido exatamente.
Se estamos falando de
COPY
instruções, uma maneira seria usar uma tabela de teste temporária e recolher duplicatas com um simples SELECT DISTINCT
ou DISTINTO ON
no INSERIR
comando:CREATE TEMP TABLE tbl_tmp AS
SELECT * FROM tbl LIMIT 0; -- copy structure without data and constraints
COPY tbl_tmp FROM '/path/to/file.csv';
INSERT INTO tbl (col1, col2, col3)
SELECT DISTINCT ON (col1, col2)
col1, col2, col3 FROM tbl_tmp;
Ou, para também proibir duplicatas com linhas já existentes:
INSERT INTO tbl (col1, col2, col3)
SELECT i.*
FROM (
SELECT DISTINCT ON (col1, col2)
col1, col2, col3
FROM tbl_tmp
) i
LEFT JOIN tbl t USING (col1, col2)
WHERE t.col1 IS NULL;
A temperatura. tabela é descartada no final da sessão automaticamente.
Mas a correção adequada seria lidar com a raiz do erro que produz duplicatas em primeiro lugar.
Pergunta original
1) Você não pode adicionar o pk, se houver uma única duplicata em todas as colunas.
2) Eu só tocaria em um banco de dados PostgreSQL versão 8.1 com um poste de cinco pés. É irremediavelmente antigo, desatualizado e ineficiente, não é mais suportado e provavelmente tem várias falhas de segurança não corrigidas. Site oficial de versão do Postgres.
@David já forneceu a instrução SQL.
3 e 4) Uma violação de chave duplicada. PostgreSQL lançando um erro também significa que toda a transação é revertida. Capturar isso em um script perl não pode fazer o resto da transação passar. Você teria que criar um script do lado do servidor com plpgsql por exemplo, onde você pode capturar exceções.