Topik wawancara representatif

Wawancara data: Bagaimana Anda menggunakan NULLS NOT DISTINCT untuk optional key di PostgreSQL 18?

DataSulit
Tim Redaksi Offer.ccDipublikasikan Diperbarui

Pertanyaan

Tabel orders mengizinkan satu referensi eksternal opsional per tenant: paling banyak satu baris per tenant yang boleh bernilai NULL. Bagaimana Anda memberlakukan ini di PostgreSQL 18 sambil menangani duplikat historis, concurrent write, dan rollback?

Prompt dan konteks

Tabel orders mengizinkan satu referensi eksternal opsional per tenant: paling banyak satu baris per tenant yang boleh bernilai NULL. Bagaimana Anda memberlakukan ini di PostgreSQL 18 sambil menangani duplikat historis, concurrent write, dan rollback?

Indeks unik default PostgreSQL memperlakukan nilai NULL sebagai nilai yang berbeda (distinct), sehingga beberapa nilai NULL tidak menimbulkan konflik. PostgreSQL 18 menambahkan NULLS NOT DISTINCT, yang membuat nilai NULL ikut serta dalam keunikan. Pertanyaan ini menguji perancangan constraint, keamanan migrasi, dan semantik konkurensi alih-alih memindahkan pemeriksaan bisnis yang rawan race condition ke dalam kode aplikasi.

Hal yang diuji oleh pewawancara

  • Apakah Anda menjelaskan keunikan NULL default versus NULLS NOT DISTINCT secara tepat.
  • Apakah Anda mengetahui bahwa opsi ini berlaku untuk indeks B-tree unik atau unique constraint, bukan perbandingan biasa.
  • Apakah Anda menemukan dan menyelesaikan kombinasi duplikat historis NULL dan non-NULL terlebih dahulu.
  • Apakah Anda merancang migrasi online, rencana penguncian (lock plan), perilaku concurrent-write, dan rollback.
  • Apakah ORM, replikasi, partisi, dan kontrak downstream tetap kompatibel.

Pertanyaan untuk diklarifikasi terlebih dahulu

  • Apakah cakupannya adalah seluruh tabel, atau satu aturan per tenant, wilayah, atau status aktif?
  • Apakah NULL berarti belum ditetapkan (unassigned), tidak diketahui (unknown), atau referensi bersama yang disengaja?
  • Apakah baris historis berisi beberapa NULL, string kosong, variasi huruf besar/kecil, atau key yang dihapus secara logis (soft-deleted)?
  • Berapa tingkat penulisan (write rate), anggaran penguncian (lock budget), dan jendela migrasi?
  • Apakah aplikasi, ORM, CDC, dan laporan mengasumsikan bahwa NULL dapat berulang?

Jawaban tiga puluh detik

“Saya akan mengklarifikasi arti NULL dan cakupannya, lalu mengaudit duplikat historis. Untuk aturan berlingkup tenant, saya akan menempatkan tenant dan referensi dalam composite unique key dengan NULLS NOT DISTINCT; opsi ini membuat NULL ikut serta dalam keunikan key tersebut tetapi tidak mengubah perbandingan three-valued logic SQL atau menjadikan kolom tersebut NOT NULL. Saya akan membersihkan atau memutuskan konflik historis, menerapkan penanganan konflik sebelum indeks dibuat, membangunnya dengan rencana penguncian dan latensi, serta menguji perilaku ORM dan CDC. Basis data menjadi otoritas final untuk konkurensi; jika semantik bisnis salah, saya melakukan rollback terhadap constraint dan kebijakan aplikasi daripada mengandalkan pre-check yang rawan race condition.”

Pembahasan mendalam langkah demi langkah

Langkah 1: Konfirmasikan arti dan cakupan NULL

Bedakan nilai yang belum ditetapkan dari nilai yang tidak diketahui. Jika NULL berarti belum ditetapkan, satu NULL mungkin merupakan aturan yang diharapkan; jika berarti tidak diketahui dan pengulangan valid, maka penerapan keunikan adalah salah. Tentukan apakah constraint bersifat global atau dikelompokkan berdasarkan tenant, wilayah, dan status aktif, lalu pilih urutan composite-key dan apakah partial index diperlukan.

Langkah 2: Pilih ekspresi basis data

PostgreSQL 18 mendukung NULLS NOT DISTINCT pada indeks unik. Default-nya memperlakukan NULL sebagai tidak sama dan mengizinkan banyak NULL. Unique constraint dapat membuat model lebih jelas, sementara indeks B-tree unik dapat sesuai untuk migrasi online. Opsi ini hanya mengubah perbandingan keunikan: WHERE value = NULL tetap mengikuti three-valued logic, dan kolom dapat tetap nullable.

Langkah 3: Audit dan bersihkan data historis

Lakukan pengelompokan berdasarkan key yang diusulkan dan hitung beberapa NULL, string kosong, variasi huruf besar/kecil, dan baris soft-deleted yang masih menempati key. Tentukan per konflik apakah akan menggabungkan pesanan, mengisi referensi, mempertahankan satu baris dan memigrasikan yang lain, atau mendokumentasikan pengecualian. Buat proses pembersihan dapat diulang (replayable) dan dapat diaudit, serta validasikan di lingkungan shadow sebelum pembuatan indeks mengungkap konflik yang belum terselesaikan.

Langkah 4: Rancang migrasi online

Rilis penanganan aplikasi yang kompatibel untuk konflik keunikan terlebih dahulu, lalu buat indeks atau constraint selama jendela pemeliharaan yang terkendali. Untuk tabel besar, evaluasi pembuatan konkuren, tingkat penguncian, ruang disk, dan latensi penulisan; pantau konflik dan transaksi berdurasi panjang sepanjang waktu. Jika tenant harus ditangani bertahap, buat aturan secara bertahap (batch) dan catat batas penyelesaian (watermark). Pertahankan pre-check lama hingga database constraint dan pemetaan error siap.

Langkah 5: Tangani konkurensi dan kontrak downstream

Indeks unik adalah penentu akhir untuk insert dan update yang bersamaan. Pola aplikasi “periksa lalu masukkan” dapat meningkatkan pesan kesalahan tetapi tidak dapat menggantikan constraint. Petakan pelanggaran keunikan ke business error yang dapat dicoba lagi (retryable) atau terlihat oleh pengguna tanpa retry tanpa batas. Periksa CDC, replikasi, skema ORM, laporan, dan cache untuk asumsi bahwa NULL dapat berulang, lalu perbarui kontrak dan peringatan (alerts).

Langkah 6: Verifikasi, pantau, dan lakukan rollback

Di staging dan canary tenant, uji satu NULL, NULL kedua, nilai non-NULL yang sama, nilai non-NULL yang berbeda, pembaruan, hapus-dan-buat-ulang, serta concurrent write. Pantau pembuatan indeks, antrean kunci (lock waits), tingkat konflik, error aplikasi, dan latensi downstream. Jika semantik atau tingkat konflik tidak dapat diterima, hentikan jalur penulisan baru, hapus constraint, pulihkan penanganan error yang kompatibel, dan pertahankan jejak audit untuk analisis.

Contoh jawaban berkualitas tinggi

Pertama-tama saya akan mengonfirmasi arti NULL dan cakupannya. Jika setiap tenant boleh memiliki satu referensi opsional, saya akan menyertakan tenant dan referensi dalam composite unique key dan menggunakan NULLS NOT DISTINCT di PostgreSQL 18. Opsi ini membuat NULL ikut serta dalam keunikan untuk key tersebut, sementara three-valued logic SQL biasa dan kolom nullable tetap tidak berubah.

Sebelum peluncuran, saya akan mengaudit beberapa NULL, string kosong, variasi huruf besar/kecil, dan baris yang dihapus secara logis, memutuskan bagaimana setiap konflik digabungkan atau diisi, dan mencatat keputusan tersebut. Saya akan menerapkan penanganan konflik keunikan sebelum membangun indeks, lalu memantau kunci, ruang penyimpanan, transaksi berdurasi panjang, dan konflik. Pengujian mencakup satu dan dua NULL, non-NULL yang sama dan berbeda, pembaruan, hapus-dan-buat-ulang, serta konkurensi. Basis data adalah otoritas final, dan ORM, CDC, laporan, serta cache harus mengadopsi kontrak yang sama; jika arti bisnis terbukti salah, saya menghapus constraint dan me-rollback kebijakan aplikasi.

Kesalahan umum

  • Mengasumsikan UNIQUE hanya mengizinkan satu NULL secara default → PostgreSQL memperlakukan NULL sebagai distinct → gunakan NULLS NOT DISTINCT secara eksplisit.
  • Memperlakukannya sebagai NOT NULL → Opsi ini masih mengizinkan satu NULL → pisahkan arti missing-value dari keunikan.
  • Hanya menggunakan pre-check aplikasi → Permintaan konkuren masih mengalami race condition → biarkan unique index basis data yang memutuskan.
  • Mengabaikan string kosong dan variasi huruf besar/kecil → Duplikat bisnis mungkin bukan konflik NULL → definisikan normalisasi dan pembersihan terlebih dahulu.
  • Membangun secara online tanpa pembersihan historis → Duplikat yang ada dapat menggagalkan atau memblokir migrasi → audit, putuskan, dan pantau transaksi berdurasi panjang.
  • Hanya mengubah basis data → ORM, CDC, dan laporan mungkin masih mengasumsikan NULL yang dapat berulang → perbarui kontrak data dan pemetaan error.

Pertanyaan lanjutan

Apakah NULLS NOT DISTINCT mengubah perbandingan NULL biasa?

Tidak. Opsi ini hanya mengubah apakah NULL bertabrakan dalam unique index. WHERE value = NULL tetap mengikuti three-valued logic SQL dan harus menggunakan IS NULL. Semantik kueri, semantik indeks, dan nullability kolom harus dijelaskan secara terpisah.

Bagaimana Anda dapat bermigrasi tanpa downtime ketika dua NULL sudah ada?

Pilih baris yang dipertahankan per tenant dan status bisnis, gabungkan atau isi yang lain, dan catat keputusan tersebut dalam tabel audit. Terapkan penanganan konflik, buat indeks secara bertahap sambil memantau penguncian dan transaksi berdurasi panjang, serta tunda tenant yang konfliknya tidak dapat diselesaikan dalam jendela migrasi.

Haruskah aturan multi-tenant menggunakan composite key atau partial index?

Jika setiap status harus unik, gunakan tenant beserta referensi dalam composite unique key. Jika hanya baris aktif yang dibatasi, partial index yang dibatasi pada status aktif mungkin lebih sesuai. Pilihan bergantung pada kontrak penghapusan, pemulihan, dan transisi status, serta harus dibuktikan dengan pengujian konkurensi.

Sumber publik

Pertanyaan terkait