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

Bagaimana cara menandai nr baris tertentu dalam tabel pada akses bersamaan

Dalam jawaban terkait yang Anda maksud:

  • PEMBARUAN Pascagres ... BATAS 1

Tujuannya adalah untuk mengunci satu baris pada suatu waktu. Ini berfungsi baik dengan atau tanpa kunci penasehat, karena tidak ada peluang untuk kebuntuan - selama Anda tidak mencoba mengunci lebih banyak baris dalam transaksi yang sama.

Contoh Anda berbeda karena Anda ingin mengunci 3000 baris sekaligus . Ada ada potensi kebuntuan, kecuali jika semua operasi tulis bersamaan mengunci baris dalam urutan konsisten yang sama. Per dokumentasi:

Pertahanan terbaik terhadap deadlock umumnya adalah menghindarinya dengan memastikan bahwa semua aplikasi yang menggunakan database memperoleh kunci pada beberapa objek dalam urutan yang konsisten.

Terapkan itu dengan ORDER BY di subkueri Anda.

UPDATE cargo_item item
SET job_id = 'SOME_UUID', job_ts = now()
FROM  ( 
   SELECT id
   FROM   cargo_item
   WHERE  state='NEW' AND job_id is null 
   ORDER  BY id
   LIMIT  3000
   FOR UPDATE
   ) sub
WHERE  item.id = sub.id;

Ini aman dan dapat diandalkan, selama semua transaksi memperoleh kunci dalam urutan yang sama dan pembaruan bersamaan dari kolom pemesanan tidak diharapkan. (Baca kotak kuning "PERHATIAN" di akhir bab ini di manual.) Jadi ini harus aman dalam kasus Anda, karena Anda tidak akan memperbarui id kolom.

Secara efektif hanya satu klien pada satu waktu yang dapat memanipulasi baris dengan cara ini. Transaksi bersamaan akan mencoba mengunci baris (terkunci) yang sama dan menunggu transaksi pertama selesai.

Kunci saran berguna jika Anda memiliki banyak atau sangat lama transaksi bersamaan (sepertinya Anda tidak melakukannya). Dengan hanya sedikit, secara keseluruhan akan lebih murah untuk hanya menggunakan kueri di atas dan membuat transaksi bersamaan menunggu giliran.

Semua dalam satu PEMBARUAN

Tampaknya akses bersamaan bukan masalah dalam pengaturan Anda. Konkurensi adalah masalah yang diciptakan oleh solusi Anda saat ini.

Sebaliknya, lakukan semuanya dalam satu UPDATE . Tetapkan kumpulan n nomor (3000 dalam contoh) untuk setiap UUID dan perbarui sekaligus. Harus tercepat.

UPDATE cargo_item c
SET    job_id = u.uuid_col
     , job_ts = now()
FROM  (
   SELECT row_number() OVER () AS rn, uuid_col
   FROM   uuid_tbl WHERE  <some_criteria>  -- or see below
   ) u
JOIN (
   SELECT (row_number() OVER () / 3000) + 1 AS rn, item.id 
   FROM   cargo_item
   WHERE  state = 'NEW' AND job_id IS NULL
   FOR    UPDATE   -- just to be sure
   ) c2 USING (rn)
WHERE  c2.item_id = c.item_id;

Poin utama

  • Pembagian bilangan bulat terpotong. Anda mendapatkan 1 untuk 3000 baris pertama, 2 untuk 3000 baris berikutnya. dll.

  • Saya memilih baris secara sewenang-wenang, Anda dapat menerapkan ORDER BY di jendela untuk row_number() untuk menetapkan baris tertentu.

  • Jika Anda tidak memiliki tabel UUID untuk dikirim (uuid_tbl ), gunakan VALUES ekspresi untuk memasok mereka. Contoh.

  • Anda mendapatkan kumpulan 3000 baris. Batch terakhir akan kekurangan 3000 jika Anda tidak menemukan kelipatan 3000 untuk ditetapkan.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Kembalikan baris SETOF dari fungsi PostgreSQL

  2. Apakah mungkin untuk mematikan pemrosesan kutipan dalam perintah Postgres COPY dengan format CSV?

  3. Nama tabel atau kolom tidak boleh diawali dengan angka?

  4. Bagaimana cara mengubah nilai default kolom di PostgreSQL?

  5. Bagaimana cara mendapatkan perbedaan hari/bulan/tahun (tanggal) antara dua tanggal?