Použít sériový sloupec
Váš plán je přidat zbytečně velký index pro 40 milionů (!) řádků. A ani si nejste jisti, že to bude jedinečné. Důrazně nedoporučuji tento způsob jednání. Přidejte seriál
sloupec a hotovo:
ALTER TABLE tbl ADD COLUMN tbl_id serial PRIMARY KEY;
To je vše, co musíte udělat. Zbytek se děje automaticky. Více v příručce nebo v těchto úzce souvisejících odpovědích:
Zhroucení automatického přírůstku primárního klíče PostgreSQL v C++
Automatické zvýšení funkce SQL
Přidání seriálu
kolona je jednorázová operace, ale drahá. Celá tabulka musí být přepsána a blokovat aktualizace po dobu trvání operace. Nejlépe bez souběžného zatížení ve vypnutých hodinách. Cituji příručku zde
:
Protože to efektivně přepíše celou tabulku, můžete také vytvořit novou tabulku se sloupcem sériového pk, vložit všechny řádky ze staré tabulky, nechat sériovou, aby se naplnila výchozími hodnotami z její sekvence, starou vypustit a přejmenovat novou. Více v těchto úzce souvisejících odpovědích:
Aktualizace databázových řádků bez zamykání tabulky v PostgreSQL 9.2
Přidat nový sloupec bez tabulky zámek?
Ujistěte se, že všechny vaše příkazy INSERT mají cílový seznam, aby je další sloupec nemohl zmást:
INSERT INTO tbl (col1, col2, ...) VALUES ...
Ne:
INSERT INTO tbl VALUES ...
seriál
je implementován pomocí integer
sloupec (4 bajty).
Je implementováno omezení primárního klíče s jedinečným indexem a NOT NULL
omezení na příslušné sloupce.
Obsah indexu je uložen podobně jako tabulky. Další fyzické úložiště je potřeba samostatně. Více o fyzickém úložišti v této související odpovědi:
Výpočet a úspora místa v PostgreSQL
Váš index by obsahoval 2 časová razítka (2 x 8 bajtů) plus dlouhý název souboru vč. cesta (~ 50 bajtů?) Tím by byl index asi o 2,5 GB větší (40 milionů x 60 .. něco bajtů) a všechny operace by byly pomalejší.
Zacházení s duplikáty
Jak se vypořádat s „importováním duplikátů“ závisí na tom, jak importujete data a jak je „duplikát“ přesně definován.
Pokud mluvíme o COPY
jedním ze způsobů by bylo použít dočasnou pracovní tabulku a sbalit duplikáty jednoduchým SELECT DISTINCT
nebo DISTINCT ON
v INSERT
příkaz:
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;
Nebo také zakázat duplikáty s již existujícími řádky:
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;
Teplota tabulka je na konci relace automaticky zrušena.
Ale správnou opravou by bylo vypořádat se s kořenem chyby, která vytváří duplikáty.
Původní otázka
1) Nelze přidat pk vůbec, pokud je ve všech sloupcích jeden duplikát.
2) Dotkl bych se pouze databáze PostgreSQL verze 8.1 s pětistopou tyčí. Je to beznadějně staré, zastaralé a neefektivní, již není podporováno a pravděpodobně má řadu neopravených bezpečnostních děr. Oficiální verzovací web Postgres.
@David
již zadal příkaz SQL.
3 a 4) Duplicitní porušení klíče. PostgreSQL vyvolá chybu také znamená, že celá transakce je vrácena zpět. Chytání toho v perl skriptu nemůže provést zbytek transakce. Museli byste vytvořit skript na straně serveru například s plpgsql, kde můžete zachytit výjimky.