लैच पर लेखों की अपनी श्रृंखला को जारी रखते हुए, इस बार मैं एपीपीEND_ONLY_STORAGE_INSERT_POINT लैच पर चर्चा करने जा रहा हूं और दिखाता हूं कि यह कैसे भारी अपडेट वर्कलोड के लिए एक बड़ी बाधा हो सकती है जहां स्नैपशॉट अलगाव के किसी भी रूप का उपयोग किया जा रहा है।
मैं दृढ़ता से अनुशंसा करता हूं कि आप इससे पहले श्रृंखला में प्रारंभिक पोस्ट पढ़ लें, ताकि आपके पास कुंडी के बारे में सभी सामान्य पृष्ठभूमि ज्ञान हो।
एपीपीEND_ONLY_STORAGE_INSERT_POINT कुंडी क्या है?
इस लैच को समझाने के लिए, मुझे स्नैपशॉट आइसोलेशन के काम करने के तरीके के बारे में थोड़ा समझाने की ज़रूरत है।
जब आप वर्जनिंग के दो रूपों में से एक को सक्षम करते हैं, तो SQL सर्वर संस्करणिंग . नामक तंत्र का उपयोग करता है पूर्व-परिवर्तन संस्करणों को संरक्षित करने के लिए संस्करण स्टोर . में एक रिकॉर्ड का टेम्पर्ड में। यह इस प्रकार किया जाता है:
- एक रिकॉर्ड की पहचान अभी-अभी बदलने वाली है।
- वर्तमान रिकॉर्ड को संस्करण स्टोर में कॉपी किया गया है।
- रिकॉर्ड बदल गया है।
- अगर रिकॉर्ड में पहले से 14-बाइट का संस्करण टैग नहीं है , एक को रिकॉर्ड के अंत में जोड़ा जाता है। टैग में एक टाइमस्टैम्प (वास्तविक समय नहीं) और संस्करण स्टोर में रिकॉर्ड के पिछले संस्करण के लिए एक सूचक होता है।
- अगर रिकॉर्ड में पहले से ही एक वर्जनिंग टैग है, तो इसे नए टाइमस्टैम्प और वर्जन स्टोर पॉइंटर से अपडेट किया जाता है।
इंस्टेंस-वाइड वर्जनिंग टाइमस्टैम्प जब भी कोई नया स्टेटमेंट या बैच शुरू होता है, या किसी भी डेटाबेस में रिकॉर्ड का नया वर्जन बनाया जाता है, जहां स्नैपशॉट आइसोलेशन का कोई भी रूप सक्षम होता है। इस टाइमस्टैम्प का उपयोग यह सुनिश्चित करने के लिए किया जाता है कि कोई क्वेरी रिकॉर्ड के सही संस्करण को संसाधित करती है।
उदाहरण के लिए, एक डेटाबेस की कल्पना करें जिसने प्रतिबद्ध स्नैपशॉट सक्षम पढ़ा था, इसलिए प्रत्येक कथन को उस समय के रिकॉर्ड को देखने की गारंटी दी जाती है जब तक कि कथन शुरू हो गया हो। वर्जनिंग टाइमस्टैम्प को स्टेटमेंट के शुरू होने पर सेट किया जाता है, इसलिए किसी भी रिकॉर्ड का सामना करना पड़ता है जिसमें उच्च टाइमस्टैम्प होता है, वह "गलत" संस्करण होता है, और इसलिए "राइट" वर्जन, स्टेटमेंट के टाइमस्टैम्प से पहले टाइमस्टैम्प के साथ, से पुनर्प्राप्त किया जाना चाहिए। संस्करण की दुकान। इस प्रक्रिया के यांत्रिकी इस पोस्ट के प्रयोजनों के लिए प्रासंगिक नहीं हैं।
तो, संस्करण स्टोर में संस्करणों को भौतिक रूप से कैसे संग्रहीत किया जाता है? ऑफ-रो कॉलम सहित पूरे पूर्व-परिवर्तन रिकॉर्ड को संस्करण स्टोर में कॉपी किया जाता है, जो 8,000-बाइट विखंडू में टूट जाता है, जो आवश्यक होने पर दो पृष्ठों तक फैल सकता है (उदाहरण के लिए, एक पृष्ठ के अंत में 2,000 बाइट्स और 6,000 बाइट्स अगले की शुरुआत)। यह विशेष-उद्देश्य संग्रहण केवल-संलग्न आवंटन इकाइयों . से बना है और केवल संस्करण स्टोर संचालन के लिए उपयोग किया जाता है। ऐसा इसलिए कहा जाता है क्योंकि नया डेटा केवल हाल ही में दर्ज किए गए संस्करण के अंत के तुरंत बाद ही जोड़ा जा सकता है। एक नई आवंटन इकाई हर बार बनाई जाती है, और यह नियमित संस्करण स्टोर सफाई को बहुत कुशल बनाने की अनुमति देता है-क्योंकि एक अनावश्यक आवंटन इकाई को आसानी से छोड़ा जा सकता है। फिर से, इसके यांत्रिकी इस पोस्ट के दायरे से बाहर हैं।
और अब हम कुंडी की परिभाषा पर आते हैं:किसी भी थ्रेड को संस्करण स्टोर में पूर्व-परिवर्तन रिकॉर्ड की प्रतिलिपि बनाने की आवश्यकता होती है, यह जानने की जरूरत है कि सम्मिलन बिंदु वर्तमान परिशिष्ट-केवल आवंटन इकाई में कहां है। यह जानकारी APPEND_ONLY_STORAGE_INSERT_POINT लैच द्वारा सुरक्षित है।
कुंडी कैसे एक अड़चन बन जाती है?
यहाँ समस्या है:केवल एक स्वीकार्य मोड है जिसमें APPEND_ONLY_STORAGE_INSERT_POINT लैच प्राप्त किया जा सकता है:EX मोड (अनन्य)। और जैसा कि आप इंट्रो पोस्ट को पढ़ने से लेकर सीरीज़ तक जानेंगे, एक बार में केवल एक थ्रेड EX मोड में लैच को होल्ड कर सकता है।
इन सभी सूचनाओं को एक साथ खींचना:जब एक या अधिक डेटाबेस में स्नैपशॉट आइसोलेशन सक्षम होता है, और उन डेटाबेस में अद्यतनों का एक उच्च-पर्याप्त समवर्ती कार्यभार होता है, तो विभिन्न कनेक्शनों द्वारा बहुत सारे संस्करण उत्पन्न किए जाएंगे, और यह कुंडी बन जाएगी जहां वर्जनिंग शामिल है, वहां अपडेट वर्कलोड बढ़ने पर टोंटी का आकार बढ़ जाता है।
बाधा दिखा रहा है
आप अपने लिए बाधा को आसानी से पुन:उत्पन्न कर सकते हैं। मैंने ऐसा इस प्रकार किया:
- cXXX नाम के पूर्णांक स्तंभों के एक समूह के साथ एक तालिका बनाई, जहां XXX एक संख्या है और DocID नामक एक अंतर पहचान स्तंभ पर एक संकुल अनुक्रमणिका है
- सभी स्तंभों के लिए यादृच्छिक मानों के साथ 100,000 रिकॉर्ड सम्मिलित किए गए
- 1 से 10,000 की सीमा में एक यादृच्छिक DocID का चयन करने के लिए एक अनंत लूप के साथ एक स्क्रिप्ट बनाई, एक यादृच्छिक कॉलम नाम का चयन करें, और कॉलम मान को 1 से बढ़ाएं (इसलिए एक संस्करण बनाना)
- नौ समान स्क्रिप्ट बनाई, लेकिन प्रत्येक एक अलग 10,000 मूल्य क्लस्टर कुंजी श्रेणी से चयन
- WRITELOG प्रतीक्षा को कम करने के लिए DELAYED_DURABILITY को FORCED पर सेट करें (जाहिर है कि आप शायद ही कभी ऐसा कर रहे होंगे, लेकिन यह डेमो उद्देश्यों के लिए अड़चन को बढ़ाने में मदद करता है)
फिर मैंने सभी दस स्क्रिप्ट एक साथ चलाई और एक्सेस मेथड्स को मापा:इंडेक्स सर्च/सेकंड काउंटर को ट्रैक करने के लिए कि कितने अपडेट हो रहे थे। मैं डेटाबेस:बैच अनुरोध/सेकंड का उपयोग नहीं कर सका क्योंकि प्रत्येक स्क्रिप्ट में केवल एक बैच (अनंत लूप) था, और मैं लेनदेन/सेकंड का उपयोग नहीं करना चाहता था क्योंकि यह आंतरिक लेनदेन के साथ-साथ प्रत्येक अद्यतन को लपेटने वाला भी हो सकता है।
जब स्नैपशॉट आइसोलेशन सक्षम नहीं था, तो SQL सर्वर 2019 चलाने वाले मेरे विंडोज 10 लैपटॉप पर, मुझे दस कनेक्शनों में प्रति सेकंड लगभग 80,000 अपडेट मिल रहे थे। फिर जब मैंने डेटाबेस के लिए सेटिंग READ_COMMMITED_SNAPSHOT को चालू किया और परीक्षण को फिर से चलाया, तो वर्कलोड थ्रूपुट लगभग 60,000 अपडेट प्रति सेकंड (थ्रूपुट में 25% गिरावट) तक गिर गया। प्रतीक्षा के आँकड़ों को देखने से, सभी प्रतीक्षाओं में से 85% LATCH_EX थीं, और कुंडी के आँकड़ों को देखने से, 100% APPEND_ONLY_STORAGE_INSERT_POINT के लिए थे।
ध्यान रखें कि मैंने अड़चन को सबसे खराब दिखाने के लिए परिदृश्य स्थापित किया है। मिश्रित कार्यभार के साथ वास्तविक जीवन के वातावरण में, स्नैपशॉट अलगाव का उपयोग करते समय थ्रूपुट ड्रॉप के लिए आम तौर पर स्वीकृत मार्गदर्शन 10-15% है।
सारांश
एक अन्य संभावित क्षेत्र जो इस अड़चन से प्रभावित हो सकता है, वह है उपलब्धता समूह पठनीय सेकेंडरी। यदि डेटाबेस प्रतिकृति को पठनीय होने के लिए सेट किया गया है, तो इसके विरुद्ध सभी क्वेरी स्वचालित रूप से स्नैपशॉट अलगाव का उपयोग करती हैं, और प्राथमिक से लॉग रिकॉर्ड के सभी रीप्ले संस्करण उत्पन्न करेंगे। प्राथमिक और कई डेटाबेस से आने वाले एक उच्च पर्याप्त अपडेट वर्कलोड के साथ, और कई डेटाबेस को पठनीय होने के लिए सेट किया गया है, और समानांतर रीडो उपलब्धता समूह सेकेंडरी के लिए आदर्श है, एपीपीEND_ONLY_STORAGE_INSERT_POINT लैच उपलब्धता समूह पठनीय सेकेंडरी पर भी एक बाधा बन सकता है, जिससे हो सकता है माध्यमिक प्राथमिक के पीछे गिर रहा है। मैंने इसका परीक्षण नहीं किया है, लेकिन यह ठीक वैसा ही तंत्र है जैसा मैंने ऊपर वर्णित किया है, इसलिए ऐसा लगता है। उस स्थिति में, ट्रेस फ़्लैग 3459 का उपयोग करके समानांतर रीडो को अक्षम करना संभव है, लेकिन इससे सेकेंडरी पर समग्र थ्रूपुट खराब हो सकता है।
उपलब्धता समूह परिदृश्य को एक तरफ रख दें, दुर्भाग्य से, स्नैपशॉट अलगाव का उपयोग नहीं करना इस अड़चन से पूरी तरह से बचने का एकमात्र तरीका है, जो एक व्यवहार्य विकल्प नहीं है यदि आपका कार्यभार स्नैपशॉट अलगाव द्वारा प्रदान किए गए शब्दार्थ पर निर्भर करता है, या आपको अवरोधन समस्याओं को कम करने के लिए इसकी आवश्यकता है (स्नैपशॉट आइसोलेशन का मतलब है कि रीड क्वेश्चन शेयर लॉक हासिल नहीं करते हैं, जो चेंज क्वेश्चन को ब्लॉक करते हैं)।
संपादित करें:नीचे दी गई टिप्पणियों से, आप SQL सर्वर 2019 में ADR का उपयोग करके * कुंडी की अड़चन को दूर * कर सकते हैं, लेकिन फिर ADR ओवरहेड के कारण प्रदर्शन बहुत खराब है। परिदृश्य जहां उच्च अद्यतन कार्यभार के कारण कुंडी एक अड़चन बन जाती है, वह एडीआर के लिए बिल्कुल मान्य उपयोग का मामला नहीं है।