sql >> Databáze >  >> RDS >> PostgreSQL

Přidání vícesloupcového primárního klíče do tabulky se 40 miliony záznamů

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.



  1. MySql:jak vytvořit poddotaz a spočítat všechny řádky, kde je id stejné, ve dvou tabulkách

  2. Jak otestovat, zda je řetězec JSON nebo ne?

  3. Oracle Cloud:Vytvoření databáze ATP (Autonomous Transaction Processing).

  4. Jak přejmenuji sloupec primárního klíče v MySQL?