SQL सर्वर प्रतिबद्ध पढ़ें . के दो भौतिक कार्यान्वयन प्रदान करता है SQL मानक द्वारा परिभाषित अलगाव स्तर, प्रतिबद्ध पढ़ने और पढ़ने के लिए प्रतिबद्ध स्नैपशॉट अलगाव को लॉक करना (RCSI ) जबकि दोनों कार्यान्वयन एसक्यूएल मानक में पढ़ने के लिए प्रतिबद्ध अलगाव व्यवहार के लिए निर्धारित आवश्यकताओं को पूरा करते हैं, आरसीएसआई के पास इस श्रृंखला में पिछली पोस्ट में देखे गए लॉकिंग कार्यान्वयन से काफी अलग भौतिक व्यवहार हैं।
तार्किक गारंटी
SQL मानक के लिए आवश्यक है कि रीड कमिटेड आइसोलेशन स्तर पर चल रहे लेन-देन को किसी भी गंदे रीड का अनुभव न हो। इस आवश्यकता को व्यक्त करने का एक अन्य तरीका यह है कि एक पढ़ा हुआ प्रतिबद्ध लेनदेन केवल प्रतिबद्ध डेटा का सामना करना चाहिए ।
मानक यह भी कहता है कि प्रतिबद्ध लेनदेन पढ़ें हो सकता है गैर-दोहराए जाने योग्य पठन और प्रेत के रूप में ज्ञात समवर्ती घटना का अनुभव करें (हालांकि उन्हें वास्तव में ऐसा करने की आवश्यकता नहीं है)। जैसा कि होता है, SQL सर्वर में रीड कमिटेड आइसोलेशन के दोनों भौतिक कार्यान्वयन गैर-दोहराए जाने योग्य रीड्स और फैंटम पंक्तियों का अनुभव कर सकते हैं, हालांकि सटीक विवरण काफी भिन्न हैं।
प्रतिबद्ध डेटा का समय-समय पर दृश्य
यदि डेटाबेस विकल्प READ_COMMITTED_SNAPSHOT
में ON
, SQL सर्वर पठन प्रतिबद्ध आइसोलेशन स्तर के पंक्ति-संस्करण कार्यान्वयन का उपयोग करता है। जब इसे सक्षम किया जाता है, तो रीड कमिटेड आइसोलेशन का अनुरोध करने वाले लेनदेन स्वचालित रूप से RCSI कार्यान्वयन का उपयोग करते हैं; RCSI का उपयोग करने के लिए मौजूदा T-SQL कोड में किसी परिवर्तन की आवश्यकता नहीं है। ध्यान से नोट करें हालांकि यह समान नहीं है यह कहते हुए कि कोड वही व्यवहार करेगा आरसीएसआई के तहत जब रीड कमिटेड के लॉकिंग कार्यान्वयन का उपयोग किया जाता है, तो वास्तव में यह आमतौर पर ऐसा नहीं है ।
SQL मानक में ऐसा कुछ भी नहीं है जिसके लिए पढ़े गए प्रतिबद्ध लेन-देन द्वारा पढ़े गए डेटा को सबसे हाल का होना आवश्यक है प्रतिबद्ध डेटा। SQL सर्वर RCSI कार्यान्वयन पॉइंट-इन-टाइम व्यू के साथ लेन-देन प्रदान करने के लिए इसका लाभ उठाता है प्रतिबद्ध डेटा का, जहां वह समय वर्तमान कथन शुरू होने का क्षण है निष्पादन (जिस क्षण कोई भी लेन-देन शुरू नहीं हुआ)।
यह SQL सर्वर लॉकिंग कार्यान्वयन के रीड कमिटेड के व्यवहार से काफी अलग है, जहां स्टेटमेंट सबसे हाल ही में प्रतिबद्ध डेटा को जिस क्षण प्रत्येक आइटम को भौतिक रूप से पढ़ा जाता है के रूप में देखता है। . रीड कमिटेड को लॉक करना साझा लॉक को जितनी जल्दी हो सके रिलीज़ करता है, इसलिए सामने आए डेटा का सेट समय में बहुत अलग बिंदुओं से आ सकता है।
संक्षेप में, पढ़ने के लिए प्रतिबद्ध लॉकिंग प्रत्येक पंक्ति को देखता है जैसा कि उस समय था जब इसे संक्षेप में बंद कर दिया गया था और शारीरिक रूप से पढ़ा गया था; RCSI सभी पंक्तियों को देखता है जैसा कि वे उस समय थे जब बयान शुरू हुआ। दोनों कार्यान्वयनों की गारंटी है कि वे कभी भी अप्रतिबद्ध डेटा नहीं देखेंगे, लेकिन उनका सामना करने वाला डेटा बहुत भिन्न हो सकता है।
समय-समय पर दृश्य के निहितार्थ
प्रतिबद्ध डेटा का समय-समय पर दृश्य देखना लॉकिंग कार्यान्वयन के अधिक जटिल व्यवहार से स्वयं-स्पष्ट रूप से बेहतर लग सकता है। उदाहरण के लिए, यह स्पष्ट है कि समय-समय पर दृश्य अनुपलब्ध पंक्तियों की समस्याओं से ग्रस्त नहीं हो सकता है या एक ही पंक्ति का कई बार सामना करना , जो दोनों लॉकिंग प्रतिबद्ध अलगाव के तहत संभव हैं।
RCSI का दूसरा महत्वपूर्ण लाभ यह है कि यह साझा ताले प्राप्त नहीं करता डेटा पढ़ते समय, क्योंकि डेटा सीधे एक्सेस किए जाने के बजाय पंक्ति संस्करण स्टोर से आता है। साझा ताले की कमी नाटकीय रूप से संगामिति में सुधार . कर सकती है असंगत ताले प्राप्त करने की तलाश में समवर्ती लेनदेन के साथ संघर्ष को समाप्त करके। इस लाभ को आमतौर पर यह कहकर सारांशित किया जाता है कि पाठक आरसीएसआई के तहत लेखकों को ब्लॉक नहीं करते हैं, और इसके विपरीत। असंगत लॉक अनुरोधों के कारण अवरोध को कम करने के एक और परिणाम के रूप में, गतिरोध . का अवसर RCSI के तहत चलने पर आमतौर पर बहुत कम हो जाता है।
हालांकि, ये लाभ लागतों और चेतावनियों के बिना नहीं आते हैं . एक बात के लिए, प्रतिबद्ध पंक्तियों के संस्करणों को बनाए रखने से सिस्टम संसाधनों की खपत होती है, इसलिए यह महत्वपूर्ण है कि भौतिक वातावरण को इससे निपटने के लिए कॉन्फ़िगर किया गया है, मुख्यतः tempdb के संदर्भ में प्रदर्शन और स्मृति/डिस्क स्थान की आवश्यकताएं।
दूसरा चेतावनी थोड़ा अधिक सूक्ष्म है:आरसीएसआई प्रतिबद्ध डेटा का एक स्नैपशॉट दृश्य प्रदान करता है जैसा था बयान की शुरुआत में, लेकिन वास्तविक डेटा को बदलने से रोकने के लिए कुछ भी नहीं है (और वे परिवर्तन किए गए हैं) जबकि आरसीएसआई कथन निष्पादित हो रहा है। कोई साझा ताले नहीं हैं, याद रखें। इस दूसरे बिंदु का एक तात्कालिक परिणाम यह है कि आरसीएसआई के तहत चलने वाला टी-एसक्यूएल कोड पुरानी जानकारी के आधार पर निर्णय ले सकता है , डेटाबेस की वर्तमान प्रतिबद्ध स्थिति की तुलना में। हम जल्द ही इस बारे में और बात करेंगे।
इससे पहले कि हम आगे बढ़ें, मैं आरसीएसआई के बारे में एक आखिरी (कार्यान्वयन-विशिष्ट) अवलोकन करना चाहता हूं। स्केलर और मल्टी-स्टेटमेंट फ़ंक्शन युक्त कथन से भिन्न आंतरिक T-SQL संदर्भ का उपयोग करके निष्पादित करें। इसका मतलब यह है कि स्केलर या मल्टी-स्टेटमेंट फंक्शन इनवोकेशन के अंदर देखा जाने वाला पॉइंट-इन-टाइम व्यू बाकी स्टेटमेंट द्वारा देखे गए पॉइंट-इन-टाइम व्यू से बाद में हो सकता है। इसके परिणामस्वरूप अनपेक्षित विसंगतियां हो सकती हैं, क्योंकि एक ही कथन के विभिन्न भागों में समय के विभिन्न बिंदुओं का डेटा दिखाई देता है . यह अजीब और भ्रमित करने वाला व्यवहार नहीं . करता है इन-लाइन फ़ंक्शंस पर लागू होते हैं, जो उसी स्नैपशॉट को उसी स्टेटमेंट में देखते हैं जिसमें वे दिखाई देते हैं।
गैर-दोहराए जाने योग्य पठन और प्रेत
डेटाबेस की प्रतिबद्ध स्थिति के एक स्टेटमेंट-लेवल पॉइंट-इन-टाइम दृश्य को देखते हुए, यह तुरंत स्पष्ट नहीं हो सकता है कि आरसीएसआई के तहत एक पढ़ा हुआ लेनदेन गैर-दोहराए जाने योग्य रीड या फैंटम पंक्ति घटना का अनुभव कैसे कर सकता है। वास्तव में, यदि हम अपनी सोच को एकल कथन . के दायरे तक सीमित रखते हैं , इनमें से कोई भी घटना RCSI के अंतर्गत संभव नहीं है।
एक ही कथन . में एक ही डेटा को कई बार पढ़ना RCSI के तहत हमेशा समान डेटा मान लौटाएगा, उन रीड्स के बीच कोई डेटा गायब नहीं होगा, और कोई नया डेटा भी दिखाई नहीं देगा। यदि आप सोच रहे हैं कि किस प्रकार का कथन एक ही डेटा को एक से अधिक बार पढ़ सकता है, तो उन प्रश्नों के बारे में सोचें जो एक ही तालिका को एक से अधिक बार संदर्भित करते हैं, शायद एक सबक्वेरी में।
स्टेटमेंट-लेवल रीड कंसिस्टेंसी डेटा के एक निश्चित स्नैपशॉट के खिलाफ जारी किए जा रहे रीड्स का एक स्पष्ट परिणाम है। कारण है कि RCSI नहीं करता है गैर-दोहराए जाने योग्य रीड्स से सुरक्षा प्रदान करना और प्रेत यह है कि ये SQL मानक घटनाएँ लेनदेन स्तर पर परिभाषित हैं। RCSI पर चल रहे लेन-देन के भीतर कई स्टेटमेंट में अलग-अलग डेटा दिखाई दे सकता है, क्योंकि प्रत्येक स्टेटमेंट में उस समय एक पॉइंट-इन-टाइम व्यू दिखाई देता है वह विशेष स्टेटमेंट शुरू किया।
संक्षेप में, प्रत्येक कथन RCSI लेन-देन के भीतर एक स्थिर प्रतिबद्ध डेटा सेट देखता है, लेकिन वह सेट उसी लेन-देन के अंदर बयानों के बीच बदल सकता है।
पुराना डेटा
हमारे टी-एसक्यूएल कोड की पुरानी जानकारी के आधार पर एक महत्वपूर्ण निर्णय लेने की संभावना थोड़ी परेशान करने वाली है। एक पल के लिए विचार करें कि RCSI के अंतर्गत चल रहे एकल स्टेटमेंट द्वारा उपयोग किया जाने वाला पॉइंट-इन-टाइम स्नैपशॉट मनमाने ढंग से पुराना हो सकता है ।
एक बयान जो काफी समय तक चलता है, डेटाबेस की प्रतिबद्ध स्थिति को देखना जारी रखेगा जैसा कि बयान शुरू होने पर था। इस बीच, स्टेटमेंट में उस समय से डेटाबेस में हुए सभी प्रतिबद्ध परिवर्तन गायब हैं।
इसका मतलब यह नहीं है कि आरसीएसआई के तहत पुराने डेटा तक पहुंचने से जुड़ी समस्याएं लंबे समय तक चलने वाली तक सीमित हैं। बयान, लेकिन निश्चित रूप से ऐसे मामलों में मुद्दे अधिक स्पष्ट हो सकते हैं।
समय का प्रश्न
पुराने डेटा का यह मुद्दा सिद्धांत रूप में सभी RCSI कथनों पर लागू होता है, चाहे वे कितनी भी जल्दी पूरा कर लें। समय खिड़की कितनी भी छोटी क्यों न हो, इस बात की संभावना हमेशा बनी रहती है कि एक समवर्ती संचालन उस डेटा सेट को संशोधित कर सकता है जिसके साथ हम काम कर रहे हैं, बिना हमें उस परिवर्तन के बारे में पता चले। आइए हम उन सरल उदाहरणों में से एक को फिर से देखें, जिनका उपयोग हमने पहले किए गए लॉकिंग के व्यवहार की खोज करते समय किया था:
INSERT dbo.OverdueInvoices SELECT I.InvoiceNumber FROM dbo.Invoices AS I WHERE I.TotalDue > ( SELECT SUM(P.Amount) FROM dbo.Payments AS P WHERE P.InvoiceNumber = I.InvoiceNumber );
RCSI के अंतर्गत चलाए जाने पर, यह कथन नहीं किसी भी प्रतिबद्ध डेटाबेस संशोधनों को देखें जो स्टेटमेंट के निष्पादित होने के बाद होते हैं। हालांकि हम लॉकिंग कार्यान्वयन के तहत छूटी हुई या बहु-पंक्ति वाली पंक्तियों की समस्याओं का सामना नहीं करेंगे, एक समवर्ती लेनदेन एक ऐसा भुगतान जोड़ सकता है जो चाहिए एक ग्राहक को एक अतिदेय भुगतान के बारे में एक सख्त चेतावनी पत्र भेजे जाने से रोकने के लिए जब ऊपर दिए गए विवरण का निष्पादन शुरू हो जाता है।
आप शायद कई अन्य संभावित समस्याओं के बारे में सोच सकते हैं जो इस परिदृश्य में हो सकती हैं, या अन्य जो अवधारणात्मक रूप से समान हैं। स्टेटमेंट जितना लंबा चलता है, डेटाबेस के बारे में उसका दृष्टिकोण उतना ही पुराना होता जाता है, और संभावित-अनपेक्षित परिणामों की गुंजाइश उतनी ही अधिक होती है।
बेशक, इस विशिष्ट उदाहरण में शमन करने वाले बहुत सारे कारक हैं। व्यवहार को पूरी तरह स्वीकार्य के रूप में देखा जा सकता है। आखिरकार, एक अनुस्मारक पत्र भेजना क्योंकि भुगतान कुछ सेकंड बहुत देर से आया है, एक आसानी से बचाव की गई कार्रवाई है। हालांकि सिद्धांत बना हुआ है।
व्यावसायिक नियम विफलताएं और सत्यनिष्ठा जोखिम
कुछ सेकंड पहले चेतावनी पत्र भेजने की तुलना में पुरानी जानकारी के उपयोग से अधिक गंभीर समस्याएँ उत्पन्न हो सकती हैं। कमजोरी के इस वर्ग का एक अच्छा उदाहरण ट्रिगर कोड . के साथ देखा जा सकता है एक अखंडता नियम को लागू करने के लिए उपयोग किया जाता है जो शायद घोषणात्मक संदर्भात्मक अखंडता बाधाओं के साथ लागू करने के लिए बहुत जटिल है। उदाहरण के लिए, निम्नलिखित कोड पर विचार करें, जो एक विदेशी कुंजी बाधा की भिन्नता को लागू करने के लिए ट्रिगर का उपयोग करता है, लेकिन एक जो केवल कुछ चाइल्ड टेबल पंक्तियों के लिए संबंध लागू करता है:
ALTER DATABASE Sandpit SET READ_COMMITTED_SNAPSHOT ON WITH ROLLBACK IMMEDIATE; GO SET TRANSACTION ISOLATION LEVEL READ COMMITTED; GO CREATE TABLE dbo.Parent (ParentID integer PRIMARY KEY); GO CREATE TABLE dbo.Child ( ChildID integer IDENTITY PRIMARY KEY, ParentID integer NOT NULL, CheckMe bit NOT NULL ); GO CREATE TRIGGER dbo.Child_AI ON dbo.Child AFTER INSERT AS BEGIN -- Child rows with CheckMe = true -- must have an associated parent row IF EXISTS ( SELECT ins.ParentID FROM inserted AS ins WHERE ins.CheckMe = 1 EXCEPT SELECT P.ParentID FROM dbo.Parent AS P ) BEGIN RAISERROR ('Integrity violation!', 16, 1); ROLLBACK TRANSACTION; END END; GO -- Insert parent row #1 INSERT dbo.Parent (ParentID) VALUES (1);
अब दूसरे सत्र में चल रहे लेन-देन पर विचार करें (यदि आप इसके साथ चल रहे हैं तो इसके लिए एक और एसएसएमएस विंडो का उपयोग करें) जो मूल पंक्ति # 1 को हटा देता है, लेकिन अभी तक प्रतिबद्ध नहीं है:
SET TRANSACTION ISOLATION LEVEL READ COMMITTED; BEGIN TRANSACTION; DELETE FROM dbo.Parent WHERE ParentID = 1;
अपने मूल सत्र में वापस, हम एक (चेक की गई) चाइल्ड पंक्ति डालने का प्रयास करते हैं जो इस माता-पिता को संदर्भित करती है:
INSERT dbo.Child (ParentID, CheckMe) VALUES (1, 1);
ट्रिगर कोड निष्पादित होता है, लेकिन क्योंकि RCSI केवल प्रतिबद्ध . देखता है विवरण के प्रारंभ होने के समय तक डेटा, यह अभी भी मूल पंक्ति (अनकमिटेड विलोपन नहीं) देखता है और सम्मिलित करना सफल होता है !
लेन-देन जिसने मूल पंक्ति को हटा दिया है, अब डेटाबेस को असंगत में छोड़कर, सफलतापूर्वक अपना परिवर्तन कर सकता है हमारे ट्रिगर तर्क के संदर्भ में स्थिति:
COMMIT TRANSACTION; SELECT P.* FROM dbo.Parent AS P; SELECT C.* FROM dbo.Child AS C;
यह निश्चित रूप से एक सरलीकृत उदाहरण है, और एक जिसे आसानी से अंतर्निहित बाधा सुविधाओं का उपयोग करके दरकिनार किया जा सकता है। बहुत अधिक जटिल व्यावसायिक नियम और छद्म-अखंडता की बाधाएं ट्रिगर के बाहर के अंदर और लिखी जा सकती हैं . RCSI के तहत गलत व्यवहार की संभावना स्पष्ट होनी चाहिए।
व्यवहार और नवीनतम-प्रतिबद्ध डेटा को अवरुद्ध करना
मैंने पहले उल्लेख किया था कि टी-एसक्यूएल कोड को उसी तरह व्यवहार करने की गारंटी नहीं है जिस तरह से आरसीएसआई रीड के तहत प्रतिबद्ध है जैसा कि उसने लॉकिंग कार्यान्वयन का उपयोग करके किया था। पिछला ट्रिगर कोड उदाहरण इसका एक अच्छा उदाहरण है, लेकिन मुझे इस बात पर ज़ोर देना होगा कि सामान्य समस्या ट्रिगर तक सीमित नहीं है ।
आरसीएसआई आम तौर पर किसी भी टी-एसक्यूएल कोड के लिए एक अच्छा विकल्प नहीं है, जिसकी शुद्धता एक समवर्ती अप्रतिबद्ध परिवर्तन मौजूद होने पर अवरुद्ध करने पर निर्भर करती है। यदि कोड वर्तमान reading पढ़ने पर निर्भर करता है तो RCSI भी सही विकल्प नहीं हो सकता है बयान शुरू होने के समय नवीनतम प्रतिबद्ध डेटा के बजाय प्रतिबद्ध डेटा। ये दो विचार संबंधित हैं, लेकिन वे एक ही चीज़ नहीं हैं।
RCSI के तहत लॉकिंग रीड प्रतिबद्ध
SQL सर्वर लॉकिंग का अनुरोध करने का एक तरीका प्रदान करता है तालिका संकेत READCOMMITTEDLOCK
. का उपयोग करके RCSI सक्षम होने पर प्रतिबद्ध पढ़ें . हम इस संकेत को तालिका में जोड़कर ऊपर दिखाई गई समस्याओं से बचने के लिए अपने ट्रिगर को संशोधित कर सकते हैं, जिसे सही ढंग से प्रदर्शन करने के लिए ब्लॉकिंग व्यवहार की आवश्यकता होती है:
ALTER TRIGGER dbo.Child_AI ON dbo.Child AFTER INSERT AS BEGIN -- Child rows with CheckMe = true -- must have an associated parent row IF EXISTS ( SELECT ins.ParentID FROM inserted AS ins WHERE ins.CheckMe = 1 EXCEPT SELECT P.ParentID FROM dbo.Parent AS P WITH (READCOMMITTEDLOCK) -- NEW!! ) BEGIN RAISERROR ('Integrity violation!', 16, 1); ROLLBACK TRANSACTION; END END;
इस बदलाव के साथ, संभावित-अनाथ चाइल्ड रो ब्लॉक को तब तक सम्मिलित करने का प्रयास किया जाता है जब तक कि डिलीट ट्रांजैक्शन नहीं हो जाता (या निरस्त हो जाता है)। यदि हटा दिया जाता है, तो ट्रिगर कोड अखंडता उल्लंघन का पता लगाता है और अपेक्षित त्रुटि उत्पन्न करता है।
उन क्वेरी की पहचान करना जो शायद ठीक से प्रदर्शन न करें RCSI के तहत एक गैर-तुच्छ कार्य है जिसके लिए व्यापक परीक्षण की आवश्यकता हो सकती है सही होने के लिए (और कृपया याद रखें कि ये मुद्दे काफी सामान्य हैं और कोड को ट्रिगर करने तक ही सीमित नहीं हैं!) साथ ही, READCOMMITTEDLOCK
जोड़ना प्रत्येक तालिका के लिए संकेत जिसकी आवश्यकता है वह एक थकाऊ और त्रुटि-प्रवण प्रक्रिया हो सकती है। जब तक SQL सर्वर आवश्यकता पड़ने पर लॉकिंग कार्यान्वयन का अनुरोध करने के लिए अधिक व्यापक दायरे वाला विकल्प प्रदान नहीं करता, तब तक हम तालिका संकेतों का उपयोग करने के साथ फंस गए हैं।
अगली बार
इस श्रृंखला की अगली पोस्ट आरसीएसआई के तहत डेटा संशोधन बयानों के आश्चर्यजनक व्यवहार पर एक नज़र के साथ, पढ़ने के लिए प्रतिबद्ध स्नैपशॉट अलगाव की हमारी परीक्षा जारी रखती है।
[ पूरी श्रृंखला के लिए सूचकांक देखें ]