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

kebuntuan di postgres pada permintaan pembaruan sederhana

Dugaan saya adalah bahwa sumber masalahnya adalah referensi kunci asing melingkar di tabel Anda.

TABLE vm_action_info
==> FOREIGN KEY (last_completed_vm_task_id) REFERENCES vm_task (id)

TABEL vm_task
==> FOREIGN KEY (vm_action_info_id) REFERENSI vm_action_info (id)

Transaksi terdiri dari dua langkah:

Ketika dua transaksi akan memperbarui catatan yang sama di vm_action_info tabel pada saat yang sama, ini akan berakhir dengan kebuntuan.

Lihat kasus uji sederhana:

CREATE TABLE vm_task
(
  id integer NOT NULL,
  version integer NOT NULL DEFAULT 0,
  vm_action_info_id integer NOT NULL,
  CONSTRAINT vm_task_pkey PRIMARY KEY (id )
)
 WITH ( OIDS=FALSE );

 insert into vm_task values 
 ( 0, 0, 0 ), ( 1, 1, 1 ), ( 2, 2, 2 );

CREATE TABLE vm_action_info(
  id integer NOT NULL,
  version integer NOT NULL DEFAULT 0,
  last_on_demand_task_id bigint,
  CONSTRAINT vm_action_info_pkey PRIMARY KEY (id )
)
WITH (OIDS=FALSE);
insert into vm_action_info values 
 ( 0, 0, 0 ), ( 1, 1, 1 ), ( 2, 2, 2 );

alter table vm_task
add  CONSTRAINT vm_action_info_fk FOREIGN KEY (vm_action_info_id)
  REFERENCES vm_action_info (id) MATCH SIMPLE
  ON UPDATE NO ACTION ON DELETE CASCADE
  ;
Alter table vm_action_info
 add CONSTRAINT vm_task_last_on_demand_task_fk FOREIGN KEY (last_on_demand_task_id)
      REFERENCES vm_task (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
      ;


Dalam sesi 1 kami menambahkan catatan ke vm_task yang merujuk ke id=2 di vm_action_info

session1=> begin;
BEGIN
session1=> insert into vm_task values( 100, 0, 2 );
INSERT 0 1
session1=>

Pada saat yang sama di sesi 2 transaksi lain dimulai:

session2=> begin;
BEGIN
session2=> insert into vm_task values( 200, 0, 2 );
INSERT 0 1
session2=>

Kemudian transaksi pertama melakukan update:

session1=> update vm_action_info set last_on_demand_task_id=100, version=version+1
session1=> where id=2;

tapi perintah ini hang dan menunggu kunci.....

lalu sesi ke-2 melakukan pembaruan ........

session2=> update vm_action_info set last_on_demand_task_id=200, version=version+1 where id=2;
BŁĄD:  wykryto zakleszczenie
SZCZEGÓŁY:  Proces 9384 oczekuje na ExclusiveLock na krotka (0,5) relacji 33083 bazy danych 16393; zablokowany przez 380
8.
Proces 3808 oczekuje na ShareLock na transakcja 976; zablokowany przez 9384.
PODPOWIEDŹ:  Przejrzyj dziennik serwera by znaleźć szczegóły zapytania.
session2=>

Deadlock terdeteksi !!!

Ini karena kedua INSERT ke dalam vm_task menempatkan kunci bersama pada baris id=2 di tabel vm_action_info karena referensi kunci asing. Kemudian pembaruan pertama mencoba menempatkan kunci tulis pada baris ini dan hang karena baris dikunci oleh transaksi (kedua) lainnya. Kemudian pembaruan kedua mencoba mengunci catatan yang sama dalam mode tulis, tetapi terkunci dalam mode bersama oleh transaksi pertama. Dan ini menyebabkan kebuntuan.

Saya pikir ini dapat dihindari jika Anda menempatkan kunci tulis pada catatan di vm_action_info, seluruh transaksi harus terdiri dari 5 langkah:

 begin;
 select * from vm_action_info where id=2 for update;
 insert into vm_task values( 100, 0, 2 );
 update vm_action_info set last_on_demand_task_id=100, 
         version=version+1 where id=2;
 commit;


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Opsi konfigurasi yang tidak didukung untuk services.db:'images'

  2. Memanggil prosedur tersimpan dalam prosedur tersimpan

  3. Bagaimana cara merepresentasikan tanggal dengan ketidakpastian di PostgreSQL

  4. relasi sudah ada setelah menambahkan bidang Many2many di odoo

  5. Bagaimana cara membuat database dengan susunan UTF-8 di PostgreSQL di Windows?