मैट और इरविन दोनों सही हैं, और मैं केवल एक और उत्तर का विस्तार कर रहा हूं कि उन्होंने इस तरह से क्या कहा जो एक टिप्पणी में फिट नहीं होगा। चूंकि उनके जवाब सभी को संतुष्ट नहीं करते हैं, और एक सुझाव था कि पोस्टग्रेक्यूएल डेवलपर्स से परामर्श किया जाना चाहिए, और मैं एक हूं, मैं विस्तार से बताऊंगा।
यहाँ महत्वपूर्ण बिंदु यह है कि SQL मानक के तहत, लेन READ COMMITTED
-देन अलगाव स्तर पर चल रहे लेन-देन के भीतर , प्रतिबंध यह है कि अप्रयुक्त लेनदेन का कार्य दिखाई नहीं देना चाहिए। जब प्रतिबद्ध लेनदेन का काम दिखाई देता है तो कार्यान्वयन-निर्भर होता है। आप जो इंगित कर रहे हैं, वह इस बात में अंतर है कि दो उत्पादों ने इसे लागू करने के लिए कैसे चुना है। न तो कार्यान्वयन मानक की आवश्यकताओं का उल्लंघन कर रहा है।
यहां पोस्टग्रेक्यूएल के भीतर क्या होता है, विस्तार से देखें:
S1-1 रन (1 पंक्ति हटाई गई)
पुरानी पंक्ति को छोड़ दिया गया है, क्योंकि S1 अभी भी वापस आ सकता है, लेकिन S1 अब पंक्ति पर एक लॉक रखता है, ताकि पंक्ति को संशोधित करने का प्रयास करने वाला कोई अन्य सत्र यह देखने के लिए प्रतीक्षा करेगा कि क्या S1 वापस आता है या रोल करता है। तालिका की कोई भी रीड अभी भी पुरानी पंक्ति देख सकती है, जब तक कि वे इसके साथ लॉक करने का प्रयास न करें SELECT FOR UPDATE
या SELECT FOR SHARE
।
S2-1 रन (लेकिन अवरुद्ध है क्योंकि S1 में राइट लॉक है)
S2 को अब S1 के परिणाम देखने के लिए इंतजार करना होगा। यदि S1 को प्रतिबद्ध होने के बजाय वापस रोल करना था, तो S2 पंक्ति को हटा देगा। ध्यान दें कि यदि S1 वापस रोल करने से पहले एक नया संस्करण सम्मिलित करता है, तो नया संस्करण कभी भी किसी अन्य लेनदेन के परिप्रेक्ष्य से नहीं होगा, और न ही पुराने संस्करण को किसी अन्य लेनदेन के परिप्रेक्ष्य से हटा दिया जाएगा।
S1-2 रन (1 पंक्ति सम्मिलित)
यह पंक्ति पुरानी से स्वतंत्र है। यदि id = 1 के साथ पंक्ति का अद्यतन किया गया था, तो पुराने और नए संस्करण संबंधित होंगे, और S2 पंक्ति के अद्यतन संस्करण को तब हटा सकता है जब यह अनब्लॉक हो गया हो। कि एक नई पंक्ति में वही मान होते हैं जो अतीत में मौजूद कुछ पंक्ति के रूप में नहीं होते हैं, लेकिन यह उस पंक्ति के अद्यतित संस्करण के समान नहीं होता है।
S1-3 रन, राइट लॉक जारी करना
इसलिए S1 के परिवर्तन कायम हैं। एक पंक्ति चली गई है। एक पंक्ति जोड़ दी गई है।
S2-1 रन, अब जब कि यह ताला प्राप्त कर सकते हैं। लेकिन 0 पंक्तियों को हटा दिया गया। हुह ???
आंतरिक रूप से क्या होता है, यह है कि अद्यतन होने पर उसी पंक्ति के अगले संस्करण में एक पंक्ति के एक संस्करण से एक सूचक होता है। यदि पंक्ति हटा दी जाती है, तो अगला संस्करण नहीं है। जब एक READ COMMITTED
लेन-देन एक ब्लॉक से एक लेखन संघर्ष पर जागता है, तो यह उस अद्यतन श्रृंखला का अंत तक अनुसरण करता है; यदि पंक्ति को हटाया नहीं गया है और यदि यह अभी भी क्वेरी के चयन मानदंडों को पूरा करती है तो इसे संसाधित किया जाएगा। यह पंक्ति हटा दी गई है, इसलिए S2 की क्वेरी आगे बढ़ती है।
तालिका के स्कैन के दौरान नई पंक्ति में S2 मिल सकता है या नहीं। यदि ऐसा होता है, तो यह देखा जाएगा कि नई पंक्ति S2 के DELETE
कथन के प्रारंभ होने के बाद बनाई गई थी , और इसलिए यह दिखाई देने वाली पंक्तियों के सेट का हिस्सा नहीं है।
यदि PostgreSQL एक नए स्नैपशॉट के साथ शुरुआत से S2 के पूरे DELETE कथन को पुनः आरंभ करने के लिए था, तो यह SQL सर्वर के समान व्यवहार करेगा। PostgreSQL समुदाय ने प्रदर्शन कारणों से ऐसा करने के लिए नहीं चुना है। इस साधारण मामले में आपको कभी भी प्रदर्शन में अंतर नजर नहीं आएगा, लेकिन DELETE
जब आप अवरुद्ध होने पर दस लाख पंक्तियों में थे , तो आप निश्चित रूप से होंगे। यहां व्यापार बंद है जहां PostgreSQL ने प्रदर्शन को चुना है, क्योंकि तेज संस्करण अभी भी मानक की आवश्यकताओं का अनुपालन करता है।
S2-2 रन, एक अद्वितीय प्रमुख बाधा उल्लंघन की रिपोर्ट करता है
बेशक, पंक्ति पहले से मौजूद है। यह तस्वीर का कम से कम आश्चर्यजनक हिस्सा है।
जबकि यहाँ कुछ आश्चर्यजनक व्यवहार है, सब कुछ SQL मानक के अनुरूप है और मानक के अनुसार "कार्यान्वयन-विशिष्ट" है। यह निश्चित रूप से आश्चर्य की बात हो सकती है यदि आप यह मान रहे हैं कि कुछ अन्य कार्यान्वयन का व्यवहार सभी कार्यान्वयनों में मौजूद होगा, लेकिन PostgreSQL READ COMMITTED
अलगाव स्तर में क्रमिक असफलता से बचने के लिए बहुत प्रयास करता है, और कुछ व्यवहारों को अनुमति देता है जो इसे प्राप्त करने के लिए अन्य उत्पादों से भिन्न होते हैं।
अब, व्यक्तिगत रूप से मैं किसी भी उत्पाद के कार्यान्वयन READ COMMITTED
में लेनदेन अलगाव स्तर का बड़ा प्रशंसक नहीं हूं । वे सभी दौड़ की स्थिति को एक व्यवहारिक दृष्टिकोण से आश्चर्यजनक व्यवहार बनाने की अनुमति देते हैं। एक बार जब कोई व्यक्ति किसी उत्पाद द्वारा अनुमत अजीब व्यवहार का आदी हो जाता है, तो वे उस "सामान्य" और दूसरे उत्पाद द्वारा चुने गए व्यापार-बंदों पर विचार करते हैं। लेकिन हर उत्पाद को किसी भी मोड के लिए किसी प्रकार का व्यापार बंद करना पड़ता है जो वास्तव में लागू नहीं होता है । जहां PostgreSQL डेवलपर्स ने अवरुद्ध को कम करने के लिए लाइन को चुनना चुना है (रीड को ब्लॉक नहीं करता है और राइट को ब्लॉक नहीं करता है पढ़ता है) और क्रमिक विफलता की संभावना को कम करने के लिए।SERIALIZABLE
READ COMMITTED
मानक के लिए आवश्यक है कि SERIALIZABLE
लेन-देन डिफ़ॉल्ट हो, लेकिन अधिकांश उत्पाद ऐसा नहीं करते क्योंकि यह अधिक लचर लेन-देन अलगाव स्तरों पर प्रदर्शन के कारण होता है। कुछ उत्पादों को वास्तव में अनुक्रमिक लेनदेन प्रदान नहीं किया SERIALIZABLE
जाता है जब चुना जाता है - सबसे उल्लेखनीय Oracle और 9.1 से पहले PostgreSQL के संस्करण। लेकिन वास्तव में SERIALIZABLE
लेन-देन का उपयोग करना दौड़ की परिस्थितियों से आश्चर्यजनक प्रभावों से बचने का एकमात्र तरीका है, और दौड़ की स्थिति SERIALIZABLE
से बचने के लिए लेनदेन को हमेशा अवरुद्ध करना चाहिए या विकासशील दौड़ की स्थिति से बचने के लिए कुछ लेनदेन को वापस करना चाहिए। SERIALIZABLE
लेन-देन का सबसे आम कार्यान्वयन स्ट्रिक्ट टू-फेज़ लॉकिंग (S2PL) है जिसमें अवरुद्ध और क्रमिक असफलता (गतिरोध के रूप में) दोनों हैं।
पूर्ण प्रकटीकरण: मैंने वास्तव में क्रमिक लेनदेन को जोड़ने के लिए MIT के डैन पोर्ट्स के साथ काम किया, जो Serializable Snapshot अलगाव नामक एक नई तकनीक का उपयोग करते हुए PostgreSQL संस्करण 9.1 में शामिल है।