PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

BUAT SKEMA JIKA TIDAK ADA menimbulkan kesalahan kunci duplikat

Ini sedikit kutil dalam implementasi IF NOT EXISTS untuk tabel dan skema. Pada dasarnya, ini adalah upaya upsert, dan PostgreSQL tidak menangani kondisi balapan dengan bersih. Aman, tapi jelek.

Jika skema sedang dibuat secara bersamaan di sesi lain tetapi belum dilakukan, maka skema itu ada dan tidak ada, tergantung pada siapa Anda dan bagaimana penampilan Anda. Tidak mungkin bagi transaksi lain untuk "melihat" skema baru di katalog sistem karena tidak dikomit, jadi ini masuk di pg_namespace tidak terlihat oleh transaksi lain. Jadi CREATE SCHEMA / CREATE TABLE mencoba membuatnya karena, sejauh yang bersangkutan, objeknya tidak ada.

Namun, itu menyisipkan baris ke dalam tabel dengan batasan unik. Batasan unik harus dapat melihat baris yang tidak dikomit agar berfungsi. Jadi insert block (berhenti) sampai transaksi pertama yang melakukan CREATE baik melakukan atau memutar kembali. Jika komit, transaksi kedua dibatalkan, karena mencoba menyisipkan baris yang melanggar batasan unik. CREATE SCHEMA tidak cukup pintar untuk menangkap kasus ini dan mencoba lagi.

Untuk memperbaiki PostgreSQL ini dengan benar mungkin perlu penguncian predikat, di mana ia dapat mengunci potensi baris . Ini mungkin ditambahkan sebagai bagian dari pekerjaan saat ini yang sedang berlangsung untuk mengimplementasikan UPSERT .

Untuk perintah khusus ini, PostgreSQL mungkin dapat melakukan bacaan kotor dari katalog sistem, di mana ia dapat melihat perubahan yang tidak dikomit. Kemudian bisa menunggu transaksi yang tidak dikomit untuk melakukan atau memutar kembali, melakukan kembali pembacaan kotor untuk melihat apakah orang lain sedang menunggu, dan coba lagi. Tapi ini akan memiliki kondisi balapan di mana orang lain mungkin membuat skema antara saat Anda membaca untuk memeriksanya dan saat Anda mencoba membuatnya.

Jadi IF NOT EXISTS varian harus:

  • Periksa untuk melihat apakah skema itu ada; jika ya, selesaikan tanpa melakukan apa pun.
  • Berusaha membuat tabel
  • Jika pembuatan gagal karena kesalahan batasan unik, coba lagi di awal
  • Jika pembuatan tabel berhasil, selesaikan

Sejauh yang saya tahu tidak ada yang menerapkan itu, atau mereka mencoba dan itu tidak diterima. Akan ada kemungkinan masalah dengan tingkat pembakaran ID transaksi, dll, dengan pendekatan ini.

Saya pikir ini semacam bug, tetapi ini adalah jenis bug "ya, kami tahu", bukan jenis bug "kami akan memperbaikinya". Jangan ragu untuk memposting ke pgsql-bug tentang hal itu; setidaknya dokumentasi harus menyebutkan peringatan ini tentang IF NOT EXISTS .

Saya tidak menyarankan melakukan DDL secara bersamaan seperti itu.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Apa cara terbaik untuk menyalin subset baris tabel dari satu database ke database lain di Postgres?

  2. bagaimana agar postgres mengabaikan sisipan dengan kunci duplikat tetapi teruskan

  3. Postgres - versi terakhir 0.14.0 dari permata pg memberikan kesalahan

  4. PostgreSQL:format interval sebagai menit

  5. Pilih data untuk jendela 15 menit - PostgreSQL