Użyj kolumny szeregowej
Twoim planem jest dodanie niepotrzebnie dużego indeksu dla 40 milionów (!) wierszy. I nie jesteś nawet pewien, czy będzie wyjątkowy. Zdecydowanie odradzałbym ten sposób działania. Dodaj serial
zamiast tego i skończ z tym:
ALTER TABLE tbl ADD COLUMN tbl_id serial PRIMARY KEY;
To wszystko, co musisz zrobić. Reszta dzieje się automatycznie. Więcej w instrukcji lub w tych ściśle powiązanych odpowiedziach:
Awaria automatycznego przyrostu klucza podstawowego PostgreSQL w C++
Funkcja automatycznej inkrementacji SQL
Dodawanie serii
kolumna jest operacją jednorazową, ale kosztowną. Cała tabela musi zostać przepisana, blokując aktualizacje na czas trwania operacji. Najlepiej robić to bez jednoczesnego obciążenia poza godzinami pracy. Cytuję instrukcję tutaj
:
Ponieważ to skutecznie przepisuje całą tabelę, równie dobrze możesz utworzyć nową tabelę z kolumną szeregowego pk, wstawić wszystkie wiersze ze starej tabeli, pozwalając szeregowemu na wypełnienie domyślnymi wartościami z jego sekwencji, upuścić starą i zmienić nazwę nowej. Więcej w tych ściśle powiązanych odpowiedziach:
Aktualizacja wierszy bazy danych bez blokowania tabeli w PostgreSQL 9.2
Dodaj nową kolumnę bez tabeli zablokować?
Upewnij się, że wszystkie instrukcje INSERT mają listę celów, a dodatkowa kolumna nie może ich pomylić:
INSERT INTO tbl (col1, col2, ...) VALUES ...
Nie:
INSERT INTO tbl VALUES ...
seryjny
jest zaimplementowany z liczbą całkowitą
kolumna (4 bajty).
Zaimplementowano ograniczenie klucza podstawowego z unikalnym indeksem i NOT NULL
ograniczenie na zaangażowanych kolumnach.
Zawartość indeksu jest przechowywana podobnie jak tabele. Dodatkowa pamięć fizyczna jest potrzebna osobno. Więcej o pamięci fizycznej w tej powiązanej odpowiedzi:
Obliczanie i oszczędzanie miejsca w PostgreSQL
Twój indeks będzie zawierał 2 sygnatury czasowe (2 x 8 bajtów) oraz długą nazwę pliku, w tym path (~ 50 bajtów?) To spowodowałoby, że indeks byłby większy o około 2,5 GB (40M x 60…coś bajtów) i wszystkie operacje byłyby wolniejsze.
Radzenie sobie z duplikatami
Sposób radzenia sobie z „importowaniem duplikatów” zależy od tego, w jaki sposób importujesz dane i jak dokładnie zdefiniowano „duplikat”.
Jeśli mówimy o KOPIUJ
instrukcji, jednym ze sposobów byłoby użycie tymczasowej tabeli pomostowej i zwinięcie duplikatów za pomocą prostego SELECT DISTINCT
lub DISTINCT ON
w WSTAW
polecenie:
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;
Lub, aby zabronić również duplikatów z już istniejącymi wierszami:
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. tabela jest automatycznie usuwana pod koniec sesji.
Ale właściwą poprawką byłoby przede wszystkim zajęcie się źródłem błędu, który powoduje duplikaty.
Pierwotne pytanie
1) Nie można było w ogóle dodać pk, jeśli istnieje jeden duplikat we wszystkich kolumnach.
2) Dotknąłbym tylko bazy danych PostgreSQL w wersji 8.1 z pięciometrowym słupem. Jest beznadziejnie stary, przestarzały i nieefektywny, nie jest już wspierany i prawdopodobnie ma wiele nienaprawionych luk w zabezpieczeniach. Oficjalna witryna wersjonowania Postgres.
@David
już dostarczył instrukcję SQL.
3 i 4) Zduplikowane naruszenie klucza. Zgłoszenie błędu przez PostgreSQL oznacza również wycofanie całej transakcji. Przechwycenie tego w skrypcie perla nie może spowodować przejścia reszty transakcji. Będziesz musiał na przykład utworzyć skrypt po stronie serwera za pomocą plpgsql, w którym możesz przechwytywać wyjątki.