Cara paling efisien untuk menambahkan kolom serial ke tabel besar

10

Apa cara tercepat untuk menambahkan kolom BIGSERIAL ke tabel besar (~ 3 Bil. Baris, ~ 174GB)?

EDIT:

  • Saya ingin kolom menjadi nilai yang ditambahkan untuk baris yang ada ( NOT NULL).
  • Saya tidak menetapkan fillfactor (yang terlihat seperti keputusan buruk dalam retrospeksi).
  • Saya tidak punya masalah dengan ruang disk, hanya ingin secepat mungkin.
Thi Duong Nguyen
sumber

Jawaban:

12

Ada apa dengan:

ALTER TABLE foo ADD column bar bigserial;

Akan diisi dengan nilai unik secara otomatis (dimulai dengan 1).

Jika Anda ingin nomor untuk setiap baris yang ada, setiap baris dalam tabel harus diperbarui . Atau tidak?

Tabel akan membengkak menjadi dua kali ukurannya jika tidak dapat menggunakan kembali tupel mati atau ruang kosong di halaman data. Kinerja operasi mungkin mendapat banyak manfaat dari FILLFACTORtupel mati yang lebih rendah dari 100 atau hanya tersebar di atas meja. Lain, Anda mungkin ingin menjalankan VACUUM FULL ANALYZEsetelah itu untuk memulihkan ruang disk. Ini tidak akan cepat.

pgstattuple
Anda mungkin tertarik dengan ekstensi ini. Ini membantu Anda mengumpulkan statistik di meja Anda. Untuk mencari tahu tentang tupel mati dan ruang kosong:

Pasang ekstensi sekali per databae:

CREATE EXTENSION pgstattuple;

Panggilan:

SELECT * FROM pgstattuple('tbl');

Alternatif

Jika Anda mampu membuat tabel baru, yang akan memecah tergantung tampilan, kunci asing, ...

Buat salinan kosong dari tabel lama:

CREATE new_tbl AS
SELECT *
FROM   old_tbl
LIMIT  0;

Tambahkan kolom bigserial:

ALTER new_tbl ADD column bar bigserial;

Masukkan data dari tabel lama, secara otomatis mengisi server besar:

INSERT INTO new_tbl
SELECT *    --  new column will be filled with default
FROM   old_tbl
ORDER  BY something; -- or don't order if you don't care: faster

Kolom bigserial baru tidak ada dalam SELECT INSERT dan akan diisi dengan nilai defaultnya secara otomatis . Anda bisa mengeja semua kolom dan menambahkan nextval()ke SELECTdaftar untuk efek yang sama.

Pastikan Anda mendapatkan semua data Anda di tabel baru.
Tambahkan indeks, batasan, pemicu yang Anda miliki di tabel lama sekarang .

DROP TABLE old_tbl;
ALTER TABLE new_tbl RENAME TO old_tbl;

Mungkin secara keseluruhan sedikit lebih cepat. Ini membuat Anda dengan meja vanili (dan indeks) tanpa mengasapi.

Anda memerlukan ruang disk kosong - sekitar ukuran meja lama, tergantung pada keadaan meja - sebagai ruang gerak. Tetapi Anda mungkin perlu sebanyak mungkin dengan metode sederhana pertama karena mengasapi meja. Sekali lagi, detailnya tergantung pada kondisi meja Anda.

Erwin Brandstetter
sumber
3
Bungkus alternatif dalam satu transaksi, itu akan jauh lebih cepat. Ini akan menghindari tambahan fsyncs
Frank Heikens