Pertanyaan
Tabel produksi PostgreSQL memerlukan CHECK atau constraint foreign-key baru. Baris yang ada saat ini mungkin melanggarnya, dan bisnis tidak dapat mentolerir pemblokiran tulis yang lama. Rancang alur mulai dari menemukan pelanggaran, menambahkan constraint NOT VALID, memperbaiki baris historis, dan menjalankan VALIDATE CONSTRAINT. Cakup aspek lock, konkurensi, pemantauan, dan penanganan kegagalan.
Hal yang diuji oleh pewawancara
- Apakah Anda membedakan perilaku lock saat menambahkan constraint dari pemindaian validasi berikutnya.
- Apakah Anda mengetahui bahwa
NOT VALIDmelewati pemindaian baris lama sementara operasi insert dan update baru tetap diperiksa. - Apakah Anda mengoordinasikan perbaikan, validasi, dan peluncuran aplikasi alih-alih mengeksekusi satu DDL yang memblokir.
- Apakah status constraint tetap terlihat dan dapat dipulihkan melalui kegagalan validasi, transaksi yang panjang, dan rollback.
Jawaban model
Mulailah dengan kueri hanya-baca untuk memperkirakan baris yang melanggar, ketersediaan indeks, dan transaksi yang berjalan lama. Selama jendela pemeliharaan yang terkontrol, jalankan ADD CONSTRAINT ... NOT VALID. Perintah ini tidak memindai baris yang ada, tetapi langsung memeriksa operasi insert dan update setelahnya; baris historis mungkin masih melanggar aturan, sehingga statusnya secara eksplisit menunggu validasi.
Perbaiki baris historis dalam batch terbatas dengan batas commit dan catatan progres. Logika perbaikan harus sesuai dengan aturan aplikasi, jadi deploy kode yang kompatibel terlebih dahulu jika diperlukan. Kemudian jalankan VALIDATE CONSTRAINT sambil mengamati waktu tunggu lock, durasi pemindaian, dan beban basis data. Validasi yang berhasil akan menandai constraint katalog sebagai valid dan menyelesaikan migrasi.
Untuk foreign key, verifikasi constraint keunikan yang sesuai pada kolom yang direferensikan serta evaluasi operasi tulis dan hapus yang bersamaan (konkuren). Jika validasi gagal, pertahankan constraint NOT VALID untuk melindungi penulisan baru, perbaiki baris yang tersisa, dan coba lagi. Lakukan drop hanya jika persyaratan tersebut benar-benar dihapus.
Alur migrasi
-- 1. Record violations and create repair work
SELECT count(*) FROM orders WHERE total < 0;
-- 2. Add the constraint without scanning historical rows
ALTER TABLE orders
ADD CONSTRAINT orders_total_nonnegative
CHECK (total >= 0) NOT VALID;
-- 3. Repair in batches, then validate
ALTER TABLE orders
VALIDATE CONSTRAINT orders_total_nonnegative;Alat migrasi harus menyimpan nama constraint, kursor batch, waktu mulai dan selesai, hasil validasi, dan operator. Sebelum peluncuran, periksa setiap jalur penulisan aplikasi terhadap aturan yang sama sehingga tugas perbaikan dan logika bisnis tidak saling menimpa data.
Manfaat NOT VALID adalah memisahkan pemindaian historis yang mahal dari langkah penambahan constraint; validasi tetap memindai tabel dan mengambil lock yang terdokumentasi, sehingga tidak sepenuhnya bebas biaya. Periksa transaksi yang berjalan lama dan lag replikasi, atur statement timeout serta peringatan lock-wait, dan jalankan validasi dalam jendela yang terkontrol.
Transaksi baru diperiksa selama validasi, sementara perbaikan data historis harus menghindari penimpaan pembaruan bisnis. Gunakan rentang indeks yang stabil dan transaksi singkat untuk setiap batch. FOR UPDATE SKIP LOCKED dapat mengambil pekerjaan jika sesuai, tetapi baris yang dilewati tidak boleh membuat metrik progres terlihat selesai.
Jebakan umum
- Menganggap
NOT VALIDmenonaktifkan constraint dan mengizinkan penulisan data kotor yang baru. - Menjalankan
VALIDATE CONSTRAINTtanpa memeriksa transaksi yang lama, waktu tunggu lock, dan kapasitas replikasi. - Memperbaiki setiap baris historis dalam satu transaksi besar, yang menyebabkan bloat, lock yang lama, dan rollback yang sulit.
- Memperbaiki CHECK tetapi mengabaikan indeks yang direferensikan dan jalur penghapusan yang diperlukan oleh foreign key.
- Menghapus (drop) constraint yang gagal sehingga kehilangan perlindungan untuk penulisan baru dan jalur remediasi selanjutnya.
Penanganan kegagalan dan rollback
Gunakan status eksplisit seperti planned, not_valid, backfilling, validating, validated, dan aborted. Simpan setiap transisi dalam tabel migrasi dan log audit. Ketika validasi menemukan pelanggaran, catat nama constraint dan sampel kunci yang telah disunting (redacted), jeda validasi, dan pertahankan constraint; setelah perbaikan, lanjutkan dari progres yang tercatat.
Jika rilis aplikasi harus di-rollback, kode kompatibilitas harus tetap menangani baris lama maupun constraint baru. Menghapus constraint NOT VALID adalah pilihan terakhir dan memerlukan konfirmasi bahwa penulisan baru tidak dapat menciptakan kembali masalah tersebut. Setiap operasi DROP CONSTRAINT harus memiliki persetujuan, pencadangan, dan rencana penambahan ulang.
Observabilitas
Pantau jumlah pelanggaran, tingkat perbaikan, perkiraan sisa waktu, progres validasi, waktu tunggu lock, usia transaksi tertua, pertumbuhan WAL, dan lag replikasi. Bedakan antara "penulisan baru melanggar constraint" dari "baris historis belum divalidasi"; keduanya memerlukan prioritas respons yang berbeda.
Setelah validasi, kueri pg_constraint.convalidated dan nama constraint untuk mengonfirmasi status katalog. Simpan hasil, rencana kueri, dan jendela beban dalam catatan migrasi. Laporan eksternal harus menggunakan kunci yang telah disunting dan data agregat, jangan pernah menyertakan data bisnis dalam log.
- PostgreSQL 17
ALTER TABLE: semantik lock dan konkurensi untukNOT VALIDdanVALIDATE CONSTRAINT. - Dokumentasi constraint PostgreSQL saat ini: aturan validasi CHECK, foreign-key, dan baris historis.
- PostgreSQL 17
pg_constraint: kolom katalog seperticonvalidated.
Pertanyaan lanjutan
Mengapa penulisan baru diperiksa sementara baris lama mungkin tetap tidak valid?
NOT VALID melewati pemindaian baris yang sudah ada saat constraint ditambahkan. Definisi tersebut tetap langsung berlaku untuk operasi INSERT dan UPDATE berikutnya, mencegah bertambahnya backlog historis.
Bisakah operasi penulisan berlanjut selama validasi?
Bisa, tetapi validasi membaca tabel dan mengambil lock yang terdokumentasi, sehingga waktu tunggu dan beban harus dikendalikan. Baris baru diperiksa, dan batch perbaikan harus menghindari penimpaan pembaruan aplikasi.
Bagaimana cara memperkirakan durasi validasi?
Gunakan ukuran tabel, rencana pemindaian, perilaku cache, beban kerja konkuren, dan jendela pemeliharaan untuk perkiraan terukur atau sampel. Jangan berasumsi bahwa jumlah baris saja bersifat linier; tetapkan kebijakan timeout dan pembatalan sebelum masuk ke produksi.
Apa yang istimewa dari migrasi foreign-key?
Verifikasi keunikan dan pengindeksan pada kolom yang direferensikan serta tentukan semantik penghapusan yang stabil. Selama validasi, perhatikan baris anak (child rows) yang ada bersamaan dengan penghapusan, pembaruan, dan konflik lock yang terjadi serentak.
Kapan Anda harus membatalkan dan menghapus constraint?
Hanya jika persyaratan tersebut ditarik kembali atau dirancang secara salah dan terdapat perlindungan alternatif. Kegagalan validasi saja bukanlah alasan untuk menghapusnya; mempertahankan NOT VALID terus melindungi data baru dan menjaga jalur remediasi.