PostgreSQL
 sql >> डेटाबेस >  >> RDS >> PostgreSQL

सरल अद्यतन क्वेरी पर पोस्टग्रेज में गतिरोध

मेरा अनुमान है कि समस्या का स्रोत आपकी तालिकाओं में एक गोलाकार विदेशी कुंजी संदर्भ है।

तालिका vm_action_info
==> विदेशी कुंजी (last_completed_vm_task_id) संदर्भ vm_task (id)

तालिका vm_task
==> विदेशी कुंजी (vm_action_info_id) संदर्भ vm_action_info (id)

लेन-देन में दो चरण होते हैं:

जब दो लेन-देन vm_action_info . में एक ही रिकॉर्ड को अपडेट करने जा रहे हों एक ही समय में तालिका, यह एक गतिरोध के साथ समाप्त होगा।

साधारण परीक्षण मामले को देखें:

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
      ;


सत्र 1 में हम vm_task में एक रिकॉर्ड जोड़ते हैं जो vm_action_info में id=2 का संदर्भ देता है

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

उसी समय सत्र 2 में एक और लेन-देन शुरू होता है:

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

फिर पहला लेन-देन अद्यतन करता है:

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

लेकिन यह कमांड हैंग हो जाता है और लॉक होने का इंतजार कर रहा होता है.....

फिर दूसरा सत्र अपडेट करता है ........

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

गतिरोध का पता चला !!!

ऐसा इसलिए है क्योंकि दोनों INSERTs vm_task में विदेशी कुंजी संदर्भ के कारण vm_action_info तालिका में पंक्ति id=2 पर एक साझा लॉक लगाते हैं। फिर पहला अपडेट इस पंक्ति पर एक राइट लॉक लगाने की कोशिश करता है और हैंग हो जाता है क्योंकि पंक्ति दूसरे (दूसरे) लेनदेन द्वारा लॉक हो जाती है। फिर दूसरा अपडेट उसी रिकॉर्ड को राइट मोड में लॉक करने की कोशिश करता है, लेकिन इसे पहले ट्रांजेक्शन द्वारा शेयर्ड मोड में लॉक कर दिया जाता है। और यह एक गतिरोध का कारण बनता है।

मुझे लगता है कि इससे बचा जा सकता है यदि आप vm_action_info में रिकॉर्ड पर एक राइट लॉक लगाते हैं, तो पूरे लेन-देन में 5 चरण शामिल होने चाहिए:

 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. ActiveRecord::AdapterNotनिर्दिष्ट डेटाबेस कॉन्फ़िगरेशन एडेप्टर निर्दिष्ट नहीं करता है

  2. AWS में Kubernetes क्लस्टर से पोस्टग्रेज RDS को एक्सेस करना

  3. जाँच कर रहा है कि क्या अजगर के तहत एक पोस्टग्रेस्क्ल टेबल मौजूद है (और शायद Psycopg2)

  4. Django - संबंध संबंध मौजूद नहीं है। python manage.py माइग्रेट नहीं चला सकता?

  5. PostgreSQL में स्टेटमेंट के निष्पादन को कैसे रोकें