sql >> Databáze >  >> RDS >> PostgreSQL

uváznutí v postgresu na jednoduchý aktualizační dotaz

Domnívám se, že zdrojem problému je kruhový odkaz na cizí klíč ve vašich tabulkách.

TABLE vm_action_info
==> CIZÍ KLÍČ (last_completed_vm_task_id) REFERENCE vm_task (id)

TABLE vm_task
==> CIZÍ KLÍČ (vm_action_info_id) REFERENCE vm_action_info (id)

Transakce se skládá ze dvou kroků:

Když dvě transakce budou aktualizovat stejný záznam v vm_action_info tabulky ve stejnou dobu, skončí to uváznutím.

Podívejte se na jednoduchý testovací případ:

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
      ;


V relaci 1 přidáme záznam do vm_task, který odkazuje na id=2 ve vm_action_info

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

Ve stejnou dobu v relaci 2 začíná další transakce:

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

Poté 1. transakce provede aktualizaci:

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

ale tento příkaz se zablokuje a čeká na zámek.....

pak 2. relace provede aktualizaci ........

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=>

Detekováno uváznutí !!!

Je to proto, že oba INSERTy do vm_task umístí sdílený zámek na řádek id=2 v tabulce vm_action_info kvůli odkazu na cizí klíč. Potom se první aktualizace pokusí umístit zámek zápisu na tento řádek a zablokuje se, protože řádek je uzamčen jinou (druhou) transakcí. Potom se druhá aktualizace pokusí uzamknout stejný záznam v režimu zápisu, ale první transakcí je uzamčen ve sdíleném režimu. A to způsobí uváznutí.

Myslím, že se tomu lze vyhnout, pokud umístíte zámek zápisu do záznamu ve vm_action_info, celá transakce se musí skládat z 5 kroků:

 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. PDO - Vložení velkého pole do databáze MySQL

  2. Převod z mysql na mysqli (mysql_fetch_array)

  3. jaký je lepší způsob, jak změnit znakovou sadu pro velké datové tabulky?

  4. Duplikace zahrnující SUM, LEFT JOIN a GROUP BY