UPgATE

2012-04-20 6 views
19

चलाते समय PostgreSQL में डेडलॉक्स मैं PostgreSQL deadlocks के बारे में थोड़ा उलझन में पढ़ रहा हूं।UPgATE

एक ठेठ गतिरोध उदाहरण है:

-- Transaction 1 
UPDATE customer SET ... WHERE id = 1 
UPDATE customer SET ... WHERE id = 2 

-- Transaction 2 
UPDATE customer SET ... WHERE id = 2 
UPDATE customer SET ... WHERE id = 1 

लेकिन क्या होगा अगर मैं कोड बदल इस प्रकार है:

-- Transaction 1 
UPDATE customer SET ... WHERE id IN (1, 2) 

-- Transaction 2 
UPDATE customer SET ... WHERE id IN (1, 2) 

गतिरोध यहाँ की संभावना हो जाएगा?

अनिवार्य रूप से मेरा प्रश्न है: दूसरे मामले में PostgreSQL लॉक पंक्तियों को एक-एक करके करता है, या पूरे स्कोप को WHERE स्थिति से ढंकता है?

अग्रिम धन्यवाद!

उत्तर

28

पोस्टग्रेएसक्यूएल में पंक्तियां लॉक हो जाएंगी क्योंकि वे वास्तव में काम करते हैं - वास्तव में, जिस तरह से यह वास्तव में काम करता है वह यह है कि प्रत्येक टुपल (पंक्ति का संस्करण) में xmin नामक सिस्टम फ़ील्ड होता है, यह इंगित करने के लिए कि किस लेनदेन ने टुपल चालू किया है (डालने या अपडेट करके) और xmax नामक सिस्टम फ़ील्ड को इंगित करने के लिए कि कौन सा लेनदेन समाप्त हो गया है (अद्यतन या हटाएं)। जब आप डेटा तक पहुंचते हैं, तो यह निर्धारित करने के लिए प्रत्येक टुपल को जांचता है कि यह आपके लेनदेन के लिए दृश्यमान है या नहीं, इन मानों के विरुद्ध अपना सक्रिय "स्नैपशॉट" जांच कर।

यदि आप एक अद्यतन और एक टुपल को निष्पादित कर रहे हैं जो आपकी खोज स्थितियों से मेल खाता है तो एक xmin है जो इसे आपके स्नैपशॉट और सक्रिय लेनदेन के एक्समैक्स के लिए दृश्यमान बनाता है, यह ब्लॉक को पूरा करने के लिए इंतजार कर रहा है। यदि लेनदेन जो पहले ट्यूपल रोल को वापस अपडेट करता है, तो आपका लेनदेन उठता है और पंक्ति को संसाधित करता है; यदि पहला लेनदेन होता है, तो आपका लेनदेन उठता है और वर्तमान लेनदेन अलगाव स्तर के आधार पर कार्रवाई करता है।

जाहिर है, अलग-अलग क्रम में पंक्तियों के साथ होने का परिणाम एक डेडलॉक है। रैम में कोई पंक्ति-स्तर लॉक नहीं है जिसे एक ही समय में सभी पंक्तियों के लिए प्राप्त किया जा सकता है, लेकिन यदि पंक्तियों को उसी क्रम में अपडेट किया जाता है तो आपके पास सर्कुलर लॉकिंग नहीं हो सकती है। दुर्भाग्य से, सुझाए गए IN(1, 2) वाक्यविन्यास इसकी गारंटी नहीं देता है। अलग-अलग सत्रों में अलग-अलग लागत कारक सक्रिय हो सकते हैं, एक पृष्ठभूमि "विश्लेषण" कार्य एक योजना और दूसरी पीढ़ी के बीच तालिका के आंकड़े बदल सकता है, या यह एक seqscan का उपयोग कर सकता है और PostgreSQL अनुकूलन से प्रभावित हो सकता है जो एक नया seqscan का कारण बनता है डिस्क I/O को कम करने के लिए पहले से ही प्रगति पर और "चारों ओर लूप" में शामिल होने के लिए।

यदि आप एक ही क्रम में एक ही समय में अपडेट करते हैं, एप्लिकेशन कोड में या कर्सर का उपयोग करते हैं, तो आपके पास केवल सरल अवरोधन होगा, न कि डेडलॉक्स। सामान्य रूप से, हालांकि, संबंधपरक डेटाबेस क्रमिक विफलताओं के लिए प्रवण होते हैं, और उन्हें ढांचे के माध्यम से एक्सेस करना सबसे अच्छा होता है जो उन्हें SQLSTATE के आधार पर पहचान लेते हैं और स्वचालित रूप से पूरे लेन-देन को प्रारंभ से पुनः प्रयास करते हैं। PostgreSQL में एक serialization विफलता हमेशा 40001 या 40P01 का SQLSTATE होगा।

http://www.postgresql.org/docs/current/interactive/mvcc-intro.html

+0

धन्यवाद! तो मेरा उदाहरण उपरोक्त कारण बन सकता है (क्योंकि हम आदेश को नहीं जानते हैं, जिसमें पंक्तियों को दोनों लेनदेन में संसाधित किया जाता है)? – vyakhir

+0

यह एक डेडलॉक का कारण बन सकता है, हालांकि यह दुर्लभ होगा; पहले उदाहरण के विपरीत (स्पष्ट रूप से विभिन्न आदेशों का चयन), जहां यह आम होगा। आप तालिका को अपडेट करने वाले प्रत्येक लेनदेन की अवधि के लिए उचित ताकत का टेबल-स्तरीय लॉक लेकर डेडलॉक्स को रद्द कर सकते हैं, लेकिन यह इलाज बीमारी से भी बदतर हो सकता है। विवरण के लिए संदर्भित दस्तावेज़ अनुभाग देखें। – kgrittn

+0

लेकिन पंक्ति अद्यतन होने के बाद PostgreSQL रिलीज लॉक करता है, लेकिन पूरा अद्यतन विवरण अभी तक समाप्त नहीं हुआ है? दूसरे शब्दों में यदि हमारे पास अपडेट का विवरण है ... जहां आईडी (1,2,3,4,5) पोस्टग्रेस्क्ल अपडेट के बाद, कहें, id = 1 के साथ पंक्ति और आईडी के साथ पंक्ति के साथ आय = 2, क्या यह पंक्ति आईडी = 1 जारी करेगा? यदि हां, तो जरूरी होने पर पंक्तियों को कैसे वापस लाया जाएगा? – vyakhir