Verwenden Sie eine serielle Spalte
Ihr Plan ist es, einen unnötig großen Index für 40 Millionen (!) Zeilen hinzuzufügen. Und Sie sind nicht einmal sicher, dass es einzigartig sein wird. Von dieser Vorgehensweise würde ich dringend abraten. Fügen Sie eine Seriennummer
Spalte stattdessen und fertig:
ALTER TABLE tbl ADD COLUMN tbl_id serial PRIMARY KEY;
Das ist alles, was Sie tun müssen. Der Rest passiert automatisch. Mehr im Handbuch oder in diesen eng verwandten Antworten:
Die automatische Inkrementierung des PostgreSQL-Primärschlüssels stürzt in C++ ab
SQL-Funktion automatisch inkrementieren
Hinzufügen einer Seriennummer
Spalte ist ein einmaliger Vorgang, aber teuer. Die gesamte Tabelle muss neu geschrieben werden, wodurch Aktualisierungen für die Dauer des Vorgangs blockiert werden. Am besten ohne gleichzeitige Last außerhalb der Geschäftszeiten. Ich zitiere das Handbuch hier
:
Da dies effektiv die gesamte Tabelle neu schreibt, können Sie genauso gut eine neue Tabelle mit einer seriellen pk-Spalte erstellen, alle Zeilen aus der alten Tabelle einfügen, die serielle Tabelle mit Standardwerten aus ihrer Sequenz füllen lassen, die alte löschen und die neue umbenennen. Mehr in diesen eng verwandten Antworten:
Aktualisieren von Datenbankzeilen ohne Sperren der Tabelle in PostgreSQL 9.2
Neue Spalte ohne Tabelle hinzufügen sperren?
Stellen Sie sicher, dass alle Ihre INSERT-Anweisungen eine Zielliste haben, dann kann eine zusätzliche Spalte sie nicht verwirren:
INSERT INTO tbl (col1, col2, ...) VALUES ...
Nicht:
INSERT INTO tbl VALUES ...
Eine Seriennummer
wird mit einem integer
implementiert Spalte (4 Bytes).
Eine Primärschlüsselbeschränkung wird mit einem eindeutigen Index und einem NOT NULL
implementiert Beschränkung auf die beteiligten Spalten.
Der Inhalt eines Indexes wird ähnlich wie Tabellen gespeichert. Zusätzlicher physischer Speicher wird separat benötigt. Mehr über physischen Speicher in dieser verwandten Antwort:
Berechnen und Platz sparen in PostgreSQL
Ihr Index würde 2 Zeitstempel (2 x 8 Bytes) plus einen langen Dateinamen inkl. Pfad (~ 50 Bytes?) Das würde den Index um 2,5 GB größer machen (40M x 60 .. etwas Bytes) und alle Operationen langsamer machen.
Umgang mit Duplikaten
Wie mit dem „Importieren von Duplikaten“ umgegangen wird, hängt davon ab, wie Sie Daten importieren und wie „Duplikat“ genau definiert ist.
Wenn wir über COPY
sprechen
Anweisungen wäre eine Möglichkeit, eine temporäre Staging-Tabelle zu verwenden und Duplikate mit einem einfachen SELECT DISTINCT
zu reduzieren oder DISTINCT ON
im INSERT
Befehl:
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;
Oder, um auch Duplikate mit bereits existierenden Zeilen zu verbieten:
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;
Die Temp. Tabelle wird am Ende der Sitzung automatisch gelöscht.
Aber die richtige Lösung wäre, sich mit der Wurzel des Fehlers zu befassen, der überhaupt zu Duplikaten führt.
Ursprüngliche Frage
1) Sie könnten das pk überhaupt nicht hinzufügen, wenn es ein einziges Duplikat über alle Spalten gibt.
2) Ich würde nur eine PostgreSQL-Datenbank Version 8.1 anfassen mit einer fünf Meter langen Stange. Es ist hoffnungslos alt, veraltet und ineffizient, wird nicht mehr unterstützt und hat wahrscheinlich eine Reihe von nicht behobenen Sicherheitslücken. Offizielle Postgres-Versionierungsseite.
@David
hat die SQL-Anweisung bereits bereitgestellt.
3 &4) Eine doppelte Schlüsselverletzung. Das Auslösen eines Fehlers durch PostgreSQL bedeutet auch, dass die gesamte Transaktion zurückgesetzt wird. Wenn Sie das in einem Perl-Skript abfangen, kann der Rest der Transaktion nicht ausgeführt werden. Sie müssten beispielsweise mit plpgsql ein serverseitiges Skript erstellen, in dem Sie Ausnahmen abfangen können.