sql >> Database teknologi >  >> RDS >> PostgreSQL

Tilføjelse af en primærnøgle med flere kolonner til en tabel med 40 millioner poster

Brug en seriel kolonne

Din plan er at tilføje et unødvendigt stort indeks for 40 millioner (!) rækker. Og du er ikke engang sikker på, at det bliver unikt. Jeg vil kraftigt fraråde den handlemåde. Tilføj en serie kode> kolonne i stedet og være færdig med den:

ÆNDRINGSTABEL tbl TILFØJ KOLONNE tbl_id seriel PRIMÆR NØGLE; 

Det er alt, du skal gøre. Resten sker automatisk. Mere i manualen eller i disse nært beslægtede svar:
PostgreSQL primær nøgle automatisk inkrement går ned i C++
Automatisk inkrementering af SQL-funktion

Tilføjelse af en serie kolonne er engangsdrift, men dyr. Hele tabellen skal omskrives, hvilket blokerer for opdateringer i hele operationens varighed. Gøres bedst uden samtidig belastning i frie timer. Jeg citerer manualen her :

Da dette effektivt omskriver hele tabellen, kan du lige så godt oprette en ny tabel med en seriel pk-kolonne, indsætte alle rækker fra den gamle tabel, lade serien fylde med standardværdier fra dens sekvens, slippe den gamle og omdøbe den nye. Mere i disse nært beslægtede svar:
Opdatering af databaserækker uden at låse tabellen i PostgreSQL 9.2
Tilføj ny kolonne uden tabel låse?

Sørg for, at alle dine INSERT-sætninger har en målliste, så kan en ekstra kolonne ikke forvirre dem:

INSERT INTO tbl (col1, col2, ...) VÆRDIER ... 

Ikke:

INSERT INTO tbl VALUES ... 

En serie er implementeret med et heltal kolonne (4 bytes).
En primær nøglebegrænsning er implementeret med et unikt indeks og en NOT NULL begrænsning på de involverede kolonner.
Indholdet af et indeks gemmes på samme måde som tabeller. Yderligere fysisk opbevaring er nødvendig separat. Mere om fysisk lagring i dette relaterede svar:
Beregning og pladsbesparelse i PostgreSQL

Dit indeks vil indeholde 2 tidsstempler (2 x 8 bytes) plus et langt filnavn inkl. sti (~ 50 bytes?) Det ville gøre indekset omkring 2,5 GB større (40M x 60 .. noget bytes) og alle operationer langsommere.

Håndtering af dubletter

Hvordan man håndterer "import af dubletter" afhænger af, hvordan du importerer data, og hvordan "duplikat" er defineret nøjagtigt.

Hvis vi taler om KOPI sætninger, ville en måde være at bruge en midlertidig iscenesættelsestabel og skjule dubletter med en simpel SELECT DISTINCT eller DISTINCT ON i INSERT kommando:

OPRET TEMP TABEL tbl_tmp ASSELECT * FRA tbl LIMIT 0; -- kopi struktur uden data og begrænsninger 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 for også at forbyde dubletter med allerede eksisterende rækker:

INSERT INTO tbl (col1, col2, col3)SELECT i.*FROM (SELECT DISTINCT ON (col1, col2) col1, col2, col3 FRA tbl_tmp ) iLEFT JOIN tbl t BRUG (col1, col2)HVOR t .col1 ER NULL;

Temp. tabellen slettes automatisk i slutningen af ​​sessionen.

Men den korrekte løsning ville være at håndtere roden af ​​fejlen, der producerer dubletter i første omgang.

Oprindeligt spørgsmål

1) Du kunne slet ikke tilføje pk'en, hvis der er en enkelt duplikat over alle kolonner.

2) Jeg ville kun røre en PostgreSQL-database version 8.1 med en fem fods stang. Det er håbløst gammelt, forældet og ineffektivt, understøttes ikke mere og har sandsynligvis en række uløste sikkerhedshuller. Officielt Postgres-versionswebsted.
@David allerede leveret SQL-sætningen.

3 &4) En dublet nøgleovertrædelse. PostgreSQL kaster en fejl betyder også, at hele transaktionen rulles tilbage. At fange det i et perl-script kan ikke få resten af ​​transaktionen til at gå igennem. Du skal for eksempel oprette et script på serversiden med plpgsql, hvor du kan fange undtagelser.



  1. app går ned på JSON jparser lav http-anmodning

  2. Kan ikke udtrække XML-værdi fra Oracle CBLOB

  3. Delphi DBX- og MySQL-forbindelsesmareridt:DBX-fejl:Driveren kunne ikke initialiseres korrekt

  4. MONTHS_BETWEEN() Funktion i Oracle