sql >> Database teknologi >  >> RDS >> PostgreSQL

dødvande i postgres på simpel opdateringsforespørgsel

Mit gæt er, at kilden til problemet er en cirkulær fremmednøglereference i dine tabeller.

TABEL vm_action_info
==> UDENLANDSKE NØGLE (last_completed_vm_task_id) REFERENCER vm_task (id)

TABEL vm_task
==> UDENLANDSKE NØGLE (vm_action_info_id) REFERENCER vm_action_info (id)

Transaktionen består af to trin:

Når to transaktioner skal opdatere den samme post i vm_action_info bordet på samme tid, vil dette afsluttes med et dødvande.

Se på en simpel testcase:

OPRET TABEL vm_task( id heltal IKKE NULL, versionsheltal IKKE NULL STANDARD 0, vm_action_info_id heltal IKKE NULL, CONSTRAINT vm_task_pkey PRIMÆR NØGLE (id )) MED ( OIDS=FALSK ); indsæt i vm_task værdier ( 0, 0, 0 ), ( 1, 1, 1 ), ( 2, 2, 2 ); CREATE TABLE vm_action_info( id heltal IKKE NULL, version heltal IKKE NULL STANDARD 0, last_on_demand_task_id bigint, CONSTRAINT_info KEY (id ))WITH (OIDS=FALSE);indsæt i vm_action_info værdier ( 0, 0, 0 ), ( 1, 1, 1 ), ( 2, 2, 2 );ændre tabel vm_taskadd CONSTRAINT vm_action_info_fk UDENLANDSKE NØGLE (vm)_action_info_id REFERENCER vm_action_info (id) MATCH SIMPLE ON UPDATE INGEN HANDLING VED SLET CASCADE;Alter table vm_action_info add CONSTRAINT vm_task_last_on_demand_task_fk UDENLANDSKE NØGLE (last_on_demand_task_id) REFERENCES NEJ ACTIONS-ID vm_task_tabel INGEN ACTIONSKODE vm_task 


I session 1 tilføjer vi en post til vm_task, der henviser til id=2 i vm_action_info

session1=> start;BEGINsession1=> indsæt i vm_task værdier( 100, 0, 2 );INSERT 0 1session1=> 

På samme tid i session 2 begynder en anden transaktion:

session2=> start;BEGINsession2=> indsæt i vm_task værdier( 200, 0, 2 );INSERT 0 1session2=> 

Derefter udfører den første transaktion opdateringen:

session1=> opdatering vm_action_info set last_on_demand_task_id=100, version=version+1session1=> hvor id=2; 

men denne kommando hænger og venter på en lås.....

så udfører 2. session opdateringen ........

session2=> update vm_action_info set last_on_demand_task_id=200, version=version+1 where id=2;BŁĄD:wykryto zakleszczenieSZCZEGÓŁY:Proces 9384 oczekuje na ExclusiveLock na krotji 33y 390 330 (0,5) zablokowany przez 3808.Proces 3808 oczekuje na ShareLock på transakcja 976; zablokowany przez 9384.PODPOWIEDŹ:Przejrzyj dziennik serwera af znaleźć szczegóły zapytania.session2=> 

Deadlock opdaget !!!

Dette skyldes, at begge INSERT'er i vm_task placerer en delt lås på række id=2 i vm_action_info-tabellen på grund af den fremmede nøglereference. Så forsøger den første opdatering at placere en skrivelås på denne række og hænger, fordi rækken er låst af en anden (anden) transaktion. Derefter forsøger den anden opdatering at låse den samme post i skrivetilstand, men den låses i delt tilstand af den første transaktion. Og dette forårsager et dødvande.

Jeg tror, ​​at dette kan undgås, hvis du placerer en skrivelås i vm_action_info, hele transaktionen skal bestå af 5 trin:

begynde; vælg * fra vm_action_info hvor id=2 for opdatering; indsæt i vm_task værdier (100, 0, 2); update vm_action_info set last_on_demand_task_id=100, version=version+1 hvor id=2; begå;

  1. Perl DBD::Oracle Modul installation

  2. To hvor betingelse for samme kolonne ved hjælp af gruppe efter

  3. Forsøger at installere innodb memcached plugin MySQL5.6.17 på ubuntu 14.04

  4. MySQL-kommando Forklar ignore LIMIT?