sql >> Databasteknik >  >> RDS >> PostgreSQL

Lägga till en primärnyckel med flera kolumner till en tabell med 40 miljoner poster

Använd en seriell kolumn

Din plan är att lägga till ett onödigt stort index för 40 miljoner (!) rader. Och du är inte ens säker på att det kommer att bli unikt. Jag skulle starkt avråda från den vägen. Lägg till en serie kod> kolumn istället och vara klar med den:

ALTER TABLE tbl ADD COLUMN tbl_id serial PRIMARY KEY;

Det är allt du behöver göra. Resten sker automatiskt. Mer i manualen eller i dessa närbesläktade svar:
PostgreSQL primärnyckel automatiskt inkrement kraschar i C++
Automatisk ökning av SQL-funktion

Lägga till en serie kolumn är engångsdrift, men dyr. Hela tabellen måste skrivas om, vilket blockerar uppdateringar under operationens varaktighet. Görs bäst utan samtidig belastning vid lediga timmar. Jag citerar handboken här :

Eftersom detta effektivt skriver om hela tabellen kan du lika gärna skapa en ny tabell med en seriell pk-kolumn, infoga alla rader från den gamla tabellen, låta serien fyllas med standardvärden från dess sekvens, släppa den gamla och byta namn på den nya. Mer i dessa närbesläktade svar:
Uppdatera databasrader utan att låsa tabellen i PostgreSQL 9.2
Lägg till ny kolumn utan tabell låsa?

Se till att alla dina INSERT-satser har en mållista, så kan en extra kolumn inte förväxla dem:

INSERT INTO tbl (col1, col2, ...) VALUES ...

Inte:

INSERT INTO tbl VALUES ...

En serie implementeras med ett heltal kolumn (4 byte).
En primärnyckelbegränsning implementeras med ett unikt index och en NOT NULL begränsning på de inblandade kolumnerna.
Innehållet i ett index lagras ungefär som tabeller. Ytterligare fysisk lagring behövs separat. Mer om fysisk lagring i detta relaterade svar:
Beräkna och spara utrymme i PostgreSQL

Ditt index skulle innehålla 2 tidsstämplar (2 x 8 byte) plus ett långt filnamn inkl. sökväg (~ 50 byte?) Det skulle göra indexet cirka 2,5 GB större (40M x 60 .. något byte) och alla operationer långsammare.

Hantera dubbletter

Hur man hanterar "importera dubbletter" beror på hur du importerar data och hur "duplicering" definieras exakt.

Om vi ​​pratar om KOPIERA satser, skulle ett sätt vara att använda en temporär mellanställningstabell och kollapsa dubbletter med en enkel SELECT DISTINCT eller DISTINCT ON i INSERT kommando:

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;

Eller för att även förbjuda dubbletter med redan befintliga rader:

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;

Temp. tabellen släpps automatiskt i slutet av sessionen.

Men den rätta lösningen skulle vara att ta itu med roten till felet som ger dubbletter i första hand.

Ursprunglig fråga

1) Du kunde inte lägga till pk alls, om det finns en enda dubblett över alla kolumner.

2) Jag skulle bara röra en PostgreSQL-databas version 8.1 med en femfots stång. Det är hopplöst gammalt, föråldrat och ineffektivt, stöds inte längre och har förmodligen ett antal ofixade säkerhetshål. Officiell Postgres-versionswebbplats.
@David har redan tillhandahållit SQL-satsen.

3 &4) Ett duplicerat nyckelbrott. Att PostgreSQL kastar ett fel innebär också att hela transaktionen återställs. Att fånga det i ett perl-skript kan inte göra att resten av transaktionen går igenom. Du måste skapa ett skript på serversidan med plpgsql till exempel, där du kan fånga undantag.



  1. Hur importerar jag en SQL Server .bak-fil till MySQL?

  2. SQL-problem med utcheckningstider

  3. Välja distinkta värden från två tabeller

  4. 4 sätt att skydda känslig information från dina kunder