Използвайте серийна колона
Вашият план е да добавите ненужно огромен индекс за 40 милиона (!) реда. И дори не сте сигурни, че ще бъде уникален. Горещо бих посъветвал да не действате по този начин. Добавете сериен
код>
вместо това и приключете с него:
ALTER TABLE tbl ADD COLUMN tbl_id serial PRIMARY KEY;
Това е всичко, което трябва да направите. Останалото става автоматично. Повече в ръководството или в тези тясно свързани отговори:
Автоматичното увеличаване на първичния ключ на PostgreSQL се срива в C++
Автоматично нарастване на SQL функция
Добавяне на сериен номер
колоната е еднократна операция, но скъпа. Цялата таблица трябва да бъде пренаписана, блокирайки актуализациите по време на операцията. Най-добре без едновременно натоварване в извънработно време. Цитирам ръководството тук
:
Тъй като това ефективно пренаписва цялата таблица, можете също така да създадете нова таблица със серийна pk колона, да вмъкнете всички редове от старата таблица, оставяйки серийния номер да запълни със стойности по подразбиране от своята последователност, да премахнете старата и да преименувате новата. Повече в тези тясно свързани отговори:
Актуализиране на редове на база данни без заключване на таблицата в PostgreSQL 9.2
Добавяне на нова колона без таблица заключване?
Уверете се, че всичките ви оператори INSERT имат целеви списък, тогава допълнителна колона не може да ги обърка:
INSERT INTO tbl (col1, col2, ...) VALUES ...
Не:
INSERT INTO tbl VALUES ...
сериен
се реализира с цяло число
колона (4 байта).
Ограничението за първичен ключ е реализирано с уникален индекс и NOT NULL
ограничение върху включените колони.
Съдържанието на индекс се съхранява подобно на таблици. Отделно е необходимо допълнително физическо хранилище. Повече за физическото съхранение в този свързан отговор:
Изчисляване и спестяване на място в PostgreSQL
Вашият индекс ще включва 2 времеви отпечатъка (2 x 8 байта) плюс дълго име на файл, вкл. път (~ 50 байта?) Това би направило индекса с около 2,5 GB по-голям (40M x 60 .. нещо байта) и всички операции по-бавни.
Справяне с дубликати
Как да се справите с „импортиране на дубликати“ зависи от това как импортирате данни и как точно е дефиниран „дубликат“.
Ако говорим за КОПИРАНЕ
изрази, един от начините би бил да се използва временна междинна таблица и да се свият дубликати с прост SELECT DISTINCT
или DISTINCT ON
в INSERT
команда:
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;
Или също така да забраните дубликати с вече съществуващи редове:
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;
Темп. таблицата се премахва автоматично в края на сесията.
Но правилното решение би било първо да се справим с корена на грешката, която създава дубликати.
Оригинален въпрос
1) Не можете изобщо да добавите pk, ако има единичен дубликат във всички колони.
2) Бих докоснал само PostgreSQL база данни версия 8.1 с петфутов стълб. Той е безнадеждно древен, остарял и неефективен, не се поддържа повече и вероятно има редица неотстранени дупки в сигурността. Официален сайт за версии на Postgres.
@David
вече предостави SQL израза.
3 и 4) Нарушение на дублиран ключ. PostgreSQL хвърля грешка също означава, че цялата транзакция е върната назад. Улавянето на това в perl скрипт не може да накара останалата част от транзакцията да премине. Ще трябва да създадете сървърен скрипт с plpgsql например, където можете да улавяте изключения.