sql >> Database >  >> RDS >> PostgreSQL

Een primaire sleutel met meerdere kolommen toevoegen aan een tabel met 40 miljoen records

Gebruik een seriële kolom

Uw plan is om een ​​onnodig grote index toe te voegen voor 40 miljoen (!) rijen. En je weet niet eens zeker of het uniek zal zijn. Ik zou die manier van handelen ten stelligste afraden. Voeg een serial kolom in plaats daarvan en klaar ermee:

ALTER TABLE tbl ADD COLUMN tbl_id serial PRIMARY KEY;

Dat is alles wat u hoeft te doen. De rest gebeurt automatisch. Meer in de handleiding of in deze nauw verwante antwoorden:
Automatisch verhogen van PostgreSQL-primaire sleutel loopt vast in C++
SQL-functie automatisch verhogen

Een serial toevoegen kolom is een eenmalige operatie, maar duur. De hele tabel moet worden herschreven, waardoor updates voor de duur van de bewerking worden geblokkeerd. Best gedaan zonder gelijktijdige belasting buiten kantooruren. Ik citeer de handleiding hier :

Aangezien dit in feite de hele tabel herschrijft, kunt u net zo goed een nieuwe tabel maken met een seriële pk-kolom, alle rijen uit de oude tabel invoegen, de seriële laten vullen met standaardwaarden uit de reeks, de oude laten vallen en de nieuwe hernoemen. Meer in deze nauw verwante antwoorden:
Databaserijen bijwerken zonder de tabel in PostgreSQL 9.2 te vergrendelen
Nieuwe kolom toevoegen zonder tabel slot?

Zorg ervoor dat al uw INSERT-instructies een doellijst hebben, dan kan een extra kolom ze niet verwarren:

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

Niet:

INSERT INTO tbl VALUES ...

Een serial is geïmplementeerd met een integer kolom (4 bytes).
Er is een primaire sleutelbeperking geïmplementeerd met een unieke index en een NOT NULL beperking op de betrokken kolommen.
De inhoud van een index wordt net als tabellen opgeslagen. Extra fysieke opslag is apart nodig. Meer over fysieke opslag in dit gerelateerde antwoord:
Ruimte berekenen en besparen in PostgreSQL

Uw index bevat 2 tijdstempels (2 x 8 bytes) plus een lange bestandsnaam incl. pad (~ 50 bytes?) Dat zou de index ongeveer 2,5 GB groter maken (40M x 60 .. iets bytes) en alle bewerkingen langzamer.

Omgaan met duplicaten

Hoe u omgaat met "dubbel importeren" hangt af van hoe u gegevens importeert en hoe "duplicaat" precies is gedefinieerd.

Als we het hebben over COPY instructies, zou een manier zijn om een ​​tijdelijke staging-tabel te gebruiken en duplicaten samen te vouwen met een eenvoudige SELECT DISTINCT of DISTINCT ON in de INSERT commando:

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;

Of, om ook duplicaten met reeds bestaande rijen te verbieden:

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;

De temp. tafel wordt aan het einde van de sessie automatisch verwijderd.

Maar de juiste oplossing zou zijn om de oorzaak van de fout aan te pakken die in de eerste plaats duplicaten produceert.

Oorspronkelijke vraag

1) U kunt de pk helemaal niet toevoegen als er een enkel duplicaat is over alle kolommen.

2) Ik zou alleen een PostgreSQL-database versie 8.1 aanraken met een paal van anderhalve meter. Het is hopeloos oud, verouderd en inefficiënt, wordt niet meer ondersteund en heeft waarschijnlijk een aantal onopgeloste beveiligingslekken. Officiële versie-site van Postgres.
@David de SQL-instructie al geleverd.

3 &4) Een dubbele sleutelovertreding. PostgreSQL die een fout geeft, betekent ook dat de hele transactie wordt teruggedraaid. Door dat in een perl-script te vangen, kan de rest van de transactie niet doorgaan. Je zou bijvoorbeeld een server-side script moeten maken met plpgsql, waar je uitzonderingen kunt opvangen.



  1. AVG ophalen waarbij nul- of nulwaarden worden genegeerd

  2. Hoe kan ik uniciteit in een tabel afdwingen?

  3. MySQL automatisch verhogen op een niet-primaire sleutel

  4. Hoe gegevens met komma's in verschillende tekens op te slaan die door een trigger gaan?