Gunakan kolom serial
Rencana Anda adalah menambahkan indeks besar yang tidak perlu untuk 40 juta (!) baris. Dan Anda bahkan tidak yakin itu akan menjadi unik. Saya akan sangat menyarankan untuk menentang rute tindakan itu. Tambahkan serial
sebagai gantinya dan selesai dengan itu:
ALTER TABLE tbl ADD COLUMN tbl_id serial PRIMARY KEY;
Itu saja yang perlu Anda lakukan. Sisanya terjadi secara otomatis. Lebih banyak di manual atau dalam jawaban yang terkait erat ini:
Peningkatan otomatis kunci utama PostgreSQL lumpuh di C++
Fungsi SQL peningkatan otomatis
Menambahkan serial
kolom adalah operasi satu kali, tapi mahal. Seluruh tabel harus ditulis ulang, memblokir pembaruan selama operasi. Paling baik dilakukan tanpa beban bersamaan di luar jam kerja. Saya mengutip manual di sini
:
Karena ini secara efektif menulis ulang seluruh tabel, Anda mungkin juga membuat tabel baru dengan kolom pk serial, menyisipkan semua baris dari tabel lama, membiarkan serial mengisi dengan nilai default dari urutannya, menghapus yang lama dan mengganti nama yang baru. Lebih lanjut dalam jawaban yang terkait erat ini:
Memperbarui baris database tanpa mengunci tabel di PostgreSQL 9.2
Tambahkan kolom baru tanpa tabel kunci?
Pastikan semua pernyataan INSERT Anda memiliki daftar target, agar kolom tambahan tidak membingungkan mereka:
INSERT INTO tbl (col1, col2, ...) VALUES ...
Bukan:
INSERT INTO tbl VALUES ...
Sebuah serial
diimplementasikan dengan integer
kolom (4 byte).
Sebuah batasan kunci utama diimplementasikan dengan indeks unik dan NOT NULL
kendala pada kolom yang terlibat.
Isi indeks disimpan seperti tabel. Penyimpanan fisik tambahan diperlukan secara terpisah. Lebih lanjut tentang penyimpanan fisik dalam jawaban terkait ini:
Menghitung dan menghemat ruang di PostgreSQL
Indeks Anda akan menyertakan 2 cap waktu (2 x 8 byte) ditambah nama file yang panjang termasuk. path (~ 50 byte?) Itu akan membuat indeks sekitar 2,5 GB lebih besar (40M x 60 .. sesuatu byte) dan semua operasi lebih lambat.
Menangani duplikat
Cara menangani "mengimpor duplikat" bergantung pada cara Anda mengimpor data dan bagaimana "duplikat" didefinisikan dengan tepat.
Jika kita berbicara tentang COPY
pernyataan, salah satu caranya adalah dengan menggunakan tabel pementasan sementara dan menciutkan duplikat dengan SELECT DISTINCT
sederhana atau DISTINCT ON
di INSERT
perintah:
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;
Atau, untuk juga melarang duplikat dengan baris yang sudah ada:
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;
suhu tabel dijatuhkan di akhir sesi secara otomatis.
Tetapi perbaikan yang tepat adalah dengan menangani akar kesalahan yang menghasilkan duplikat sejak awal.
Pertanyaan awal
1) Anda tidak dapat menambahkan pk sama sekali, jika ada satu duplikat di semua kolom.
2) Saya hanya akan menyentuh database PostgreSQL versi 8.1 dengan tiang lima kaki. Ini sangat kuno, ketinggalan jaman dan tidak efisien, tidak didukung lagi dan mungkin memiliki sejumlah lubang keamanan yang tidak diperbaiki. Situs versi Postgres resmi.
@David
sudah menyediakan pernyataan SQL.
3 &4) Pelanggaran kunci duplikat. PostgreSQL melempar kesalahan juga berarti seluruh transaksi dibatalkan. Menangkap itu dalam skrip Perl tidak dapat membuat sisa transaksi berjalan. Anda harus membuat skrip sisi server dengan plpgsql misalnya, di mana Anda dapat menangkap pengecualian.