ईटीएल और विभिन्न रिपोर्टिंग परिदृश्यों में एक सामान्य आवश्यकता पृष्ठभूमि में एक SQL सर्वर स्टेजिंग टेबल को चुपचाप लोड करना है, ताकि डेटा की क्वेरी करने वाले उपयोगकर्ता राइट्स और इसके विपरीत से प्रभावित न हों। चाल यह है कि आप डेटा के नए, ताज़ा संस्करण पर उपयोगकर्ताओं को कैसे और कब इंगित करते हैं।
स्टेजिंग टेबल का सरलीकृत उदाहरण:एक किसान बाजार सादृश्य
तो, SQL में एक स्टेजिंग टेबल क्या है? एक वास्तविक दुनिया के उदाहरण का उपयोग करके एक स्टेजिंग टेबल को और अधिक आसानी से समझा जा सकता है:मान लें कि आपके पास सब्जियों से भरी एक टेबल है जिसे आप स्थानीय किसान बाजार में बेच रहे हैं। जैसे-जैसे आपकी सब्जियां बिकती हैं और आप नई इन्वेंट्री लाते हैं:
- जब आप ढेर सारी नई सब्जियां लाते हैं, तो आपको टेबल को खाली करने और बचे हुए स्टॉक को नए उत्पाद से बदलने में 20 मिनट का समय लगेगा।
- आप नहीं चाहते कि ग्राहक वहां बैठें और स्विच होने के लिए 20 मिनट प्रतीक्षा करें, क्योंकि अधिकांश को अपनी सब्जियां कहीं और मिल जाएंगी।
अब, क्या होगा यदि आपके पास दूसरी खाली टेबल है जहां आप नई सब्जियां लोड करते हैं, और जब आप ऐसा कर रहे हैं, तब भी ग्राहक पहली टेबल से पुरानी सब्जियां खरीद सकते हैं? (आइए दिखाते हैं कि ऐसा इसलिए नहीं है क्योंकि पुरानी सब्जियां खराब हो गई हैं या अन्यथा कम वांछनीय हैं।)
SQL सर्वर में तालिकाओं को ताज़ा करना
सक्रिय रूप से पूछताछ के दौरान संपूर्ण तालिकाओं को पुनः लोड करने के कई तरीके हैं; दो दशक पहले, मैंने sp_rename
. का बेलगाम फायदा उठाया था - मैं टेबल की एक खाली शैडो कॉपी के साथ एक शेल गेम खेलूंगा, खुशी से शैडो कॉपी को फिर से लोड करूंगा और फिर केवल लेन-देन के अंदर नाम बदलूंगा।
SQL सर्वर 2005 में, मैंने टेबल की छाया प्रतियों को रखने के लिए स्कीमा का उपयोग करना शुरू कर दिया था, जिसे मैंने उसी शेल गेम तकनीक का उपयोग करके स्थानांतरित किया था, जिसके बारे में मैंने इन दो पोस्टों में लिखा था:
- ट्रिक शॉट्स:स्कीमा स्विच-ए-रू
- स्कीमा स्विच-ए-रू, भाग 2
स्कीमा के बीच ऑब्जेक्ट्स को नाम बदलने पर स्थानांतरित करने का एकमात्र लाभ यह है कि किसी ऑब्जेक्ट का नाम बदलने के बारे में कोई चेतावनी संदेश नहीं है - जो कि एक समस्या भी नहीं है, चेतावनी संदेशों को छोड़कर एजेंट इतिहास लॉग को बहुत तेज़ी से भरते हैं।
दोनों दृष्टिकोणों को अभी भी एक स्कीमा संशोधन (एसएच-एम) लॉक की आवश्यकता है, इसलिए उन्हें किसी भी मौजूदा लेनदेन के लिए अपने स्वयं के ताले जारी करने की प्रतीक्षा करनी चाहिए। एक बार जब वे अपना एसएच-एम लॉक प्राप्त कर लेते हैं, तो वे स्कीमा स्थिरता लॉक (एसएच-एस) की आवश्यकता वाले किसी भी बाद के प्रश्नों को अवरुद्ध कर देते हैं ... जो लगभग हर क्वेरी है। यह तेजी से एक अवरुद्ध श्रृंखला दुःस्वप्न बन सकता है, क्योंकि एसएच-एस की आवश्यकता वाले किसी भी नए प्रश्न को एसएच-एम के पीछे कतार में लगना पड़ता है। (और नहीं, आप RCSI या NOLOCK
. का उपयोग करके इससे निजात नहीं पा सकते हैं हर जगह, चूंकि उन प्रश्नों के लिए भी अभी भी Sch-S की आवश्यकता है। आप Sch-S को Sch-M के साथ प्राप्त नहीं कर सकते, क्योंकि वे असंगत हैं—माइकल जे. स्वार्ट इसके बारे में यहां बात करते हैं।)
केंद्र लिटिल ने वास्तव में अपनी पोस्ट "स्टेजिंग डेटा:लॉकिंग डेंजर विद ऑल्टर स्कीम ट्रांसफर" में स्कीमा ट्रांसफर के साथ खतरों के बारे में मेरी आँखें खोलीं। वहां वह दिखाती है कि स्कीमा स्थानांतरण नाम बदलने से भी बदतर क्यों हो सकता है। बाद में उन्होंने तालिकाओं को बाहर निकालने का एक तीसरा और बहुत कम प्रभावशाली तरीका बताया, जिसका मैं अब विशेष रूप से उपयोग करता हूं:विभाजन स्विचिंग। यह विधि स्विच को कम प्राथमिकता पर प्रतीक्षा करने की अनुमति देती है, जो कि नाम बदलने या स्कीमा स्थानांतरण तकनीकों के साथ एक विकल्प भी नहीं है। जो सैक ने SQL सर्वर 2014 में वापस जोड़े गए इस एन्हांसमेंट के बारे में विस्तार से बताया:"SQL Server 2014 CTP1 में लो प्रायोरिटी लॉक वेट ऑप्शंस को एक्सप्लोर करना।"
SQL सर्वर विभाजन स्विचिंग उदाहरण
आइए एक बुनियादी उदाहरण देखें, यहां केंद्र के संपूर्ण सार का अनुसरण करते हुए। सबसे पहले, हम दो नए डेटाबेस बनाएंगे:
डेटाबेस न्यूवे बनाएं;डेटाबेस ओल्डवे बनाएं;जाओ
नए डेटाबेस में, हम अपनी सब्जी की इन्वेंट्री रखने के लिए एक टेबल बनाएंगे, और हमारे शेल गेम के लिए टेबल की दो कॉपी:
NewWay का उपयोग करें;गो क्रिएट टेबल dbo.Vegetables_NewWay(VegativeID int, Name sysname, WhyPicked datetime, BackStory nvarchar(max));GO -- हमें टेबल की दो अतिरिक्त कॉपी बनाने की जरूरत है। तालिका बनाएं dbo.Vegetables_NewWay_prev (वेजिटेबल आईडी इंट, नाम sysname, जब चुना गया डेटाटाइम, बैकस्टोरी nvarchar (अधिकतम)); टेबल डीबीओ बनाएं। वेजिटेबल्स_न्यूवे_होल्ड (वेजिटेबल आईडी इंट, नाम sysname, व्हेन पिक्ड डेटटाइम, बैकस्टोरी)); GO
हम एक ऐसी प्रक्रिया बनाते हैं जो टेबल की स्टेजिंग कॉपी को लोड करती है, फिर मौजूदा कॉपी को स्विच आउट करने के लिए ट्रांजेक्शन का उपयोग करती है।
CREATE PROCEDURE dbo.DoTheVeggieSwap_NewWayASBEGIN SET NOCOUNT ON; TRUNCATE TABLE dbo.Vegetables_NewWay_prev; INSERT dbo.Vegetables_NewWay_prev सेलेक्ट टॉप (1000000) s.session_id, o.name, s.last_successful_logon, LEFT(m.definition, 500) sys.dm_exec_sessions AS के मॉडल के रूप में। all_sql_modules एएस एम ऑन ओ। [ऑब्जेक्ट_आईडी] =एम। [ऑब्जेक्ट_आईडी]; -- यहाँ Sch-M लॉक लेने की आवश्यकता है:BEGIN TRANSACTION; (WAIT_AT_LOW_PRIORITY (MAX_DURATION =1 मिनट, ABORT_AFTER_WAIT =BLOCKERS)); ALTER TABLE dbo.Vegetables_NewWay_prev dbo पर स्विच करें।Vegetables_NewWay; प्रतिबद्ध लेनदेन; -- और अब उपयोगकर्ता dbo में नए डेटा को क्वेरी करेंगे -- पुरानी कॉपी को वापस स्विच कर सकते हैं और उसे काट सकते हैं -- अन्य प्रश्नों में हस्तक्षेप किए बिना ALTER TABLE dbo.Vegetables_NewWay_hold SWITCH TO dbo.Vegetables_NewWay_prev; TRUNCATE TABLE dbo.Vegetables_NewWay_prev;ENDGO
WAIT_AT_LOW_PRIORITY
. की खूबसूरती क्या आप ABORT_AFTER_WAIT
. के साथ व्यवहार को पूरी तरह से नियंत्रित कर सकते हैं? विकल्प:
ABORT_AFTER_WAIT सेटिंग | विवरण / लक्षण |
---|---|
स्व | इसका मतलब है कि स्विच छोड़ देगा n . के बाद मिनट।
स्विच करने का प्रयास करने वाले सत्र के लिए, यह त्रुटि संदेश के रूप में सामने आएगा: लॉक अनुरोध टाइम आउट अवधि पार हो गई है। |
ब्लॉकर्स | यह निर्देश देता है कि स्विच n तक प्रतीक्षा करेगा मिनट, फिर आगे के सभी अवरोधकों को मारकर . खुद को पंक्ति के सामने के लिए मजबूर करें । तालिका के साथ इंटरैक्ट करने का प्रयास करने वाले सत्र जो स्विच ऑपरेशन से टकराते हैं, इन त्रुटि संदेशों के कुछ संयोजन देखेंगे: उच्च प्राथमिकता वाले DDL संचालन के कारण आपका सत्र डिस्कनेक्ट कर दिया गया है।निष्पादन जारी नहीं रख सकता क्योंकि सत्र समाप्त स्थिति में है। वर्तमान आदेश पर एक गंभीर त्रुटि उत्पन्न हुई। परिणाम, यदि कोई हों, को छोड़ देना चाहिए। |
कोई नहीं | इसका मतलब है कि MAX_DURATION पर ध्यान दिए बिना, स्विच अपनी बारी आने तक खुशी-खुशी प्रतीक्षा करेगा ।
यह वही व्यवहार है जो आपको |
BLOCKERS
विकल्प चीजों को संभालने का सबसे अनुकूल तरीका नहीं है, क्योंकि आप पहले से ही कह रहे हैं कि इस स्टेजिंग / स्विच ऑपरेशन के माध्यम से उपयोगकर्ताओं के लिए डेटा को देखना ठीक है जो थोड़ा पुराना है। मैं संभवतः SELF
. का उपयोग करना पसंद करूंगा/करूंगी और उन मामलों में फिर से ऑपरेशन का प्रयास करें जहां उसे आवंटित समय में आवश्यक ताले नहीं मिल सके। मैं इस बात पर नज़र रखता हूँ कि यह कितनी बार विफल होता है, हालाँकि, विशेष रूप से लगातार विफलताएँ, क्योंकि आप यह सुनिश्चित करना चाहते हैं कि डेटा कभी भी पुराना न हो।
स्कीमा के बीच स्विच करने के पुराने तरीके की तुलना में
यहां बताया गया है कि मैंने पहले स्विचिंग को कैसे संभाला होगा:
ओल्डवे का उपयोग करें; जाओ - दो स्कीमा और तालिका की दो प्रतियां बनाएं स्कीमा बनाएं पिछला प्राधिकरण डीबीओ बनाएं; स्कीमा बनाएं प्राधिकरण डीबीओ बनाएं; टेबल डीबीओ बनाएं। सब्जियां_ओल्डवे (वेजिटेबल आईडी इंट, नाम sysname, जब चुना गया डेटाटाइम, बैकस्टोरी मैक्स));गो क्रिएट टेबल प्रीव। वेजिटेबल्स_ओल्डवे (वेजिटेबलआईडी इंट, नेम सिसनाम, व्हेन पिक्ड डेटटाइम, बैकस्टोरी नवरचर (मैक्स)); GO CREATE PROCEDURE dbo.DoTheVeggieSwap_OldWayASBEGIN SET NOCOUNT ON; TRUNCATE TABLE prev.Vegetables_OldWay; INSERT prev.Vegetables_OldWay SELECT TOP (1000000) s.session_id, o.name, s.last_successful_logon, LEFT(m.definition, 500) sys.dm_exec_sessions AS s CROSS JOIN model.sys.all_objects AS मॉडल.sys. all_sql_modules एएस एम ऑन ओ। [ऑब्जेक्ट_आईडी] =एम। [ऑब्जेक्ट_आईडी]; -- यहाँ Sch-M लॉक लेने की आवश्यकता है:BEGIN TRANSACTION; ALTER SCHEMA होल्ड ट्रांसफर dbo.Vegetables_OldWay; ALTER SCHEMA dbo TRANSFER prev.Vegetables_OldWay; प्रतिबद्ध लेनदेन; -- और अब उपयोगकर्ता dbo में नए डेटा को क्वेरी करेंगे -- पुरानी प्रतिलिपि को वापस स्थानांतरित कर सकते हैं और बिना अन्य प्रश्नों में हस्तक्षेप किए उसे काट सकते हैं:ALTER SCHEMA prev TRANSFER Hold.Vegetables_OldWay; TRUNCATE TABLE prev.Vegetables_OldWay;ENDGO
मैंने एरिक इजल्सकोव जेन्सेन की SQLQueryStress की दो विंडो का उपयोग करके समवर्ती परीक्षण चलाया:एक हर मिनट प्रक्रिया के लिए एक कॉल दोहराने के लिए, और दूसरा इस तरह से 16 थ्रेड चलाने के लिए, हजारों बार:
लेनदेन शुरू करें; अद्यतन शीर्ष (1) डीबीओ।
अवधि और त्रुटि दर | स्कीमा ट्रांसफर | ABORT_AFTER_WAIT: SELF | ABORT_AFTER_WAIT: BLOCKERS |
---|---|---|---|
औसत अवधि - स्थानांतरण/स्विच | 96.4 सेकंड | 68.4 सेकंड | 20.8 सेकंड |
औसत अवधि - DML | 18.7 सेकंड | 2.7 सेकंड | 2.9 सेकंड |
अपवाद - स्थानांतरण/स्विच | 0 | 0.5/मिनट | 0 |
अपवाद - DML | 0 | 0 | 25.5/मिनट |
ध्यान दें कि अवधि और अपवाद की संख्या आपके सर्वर विनिर्देशों पर अत्यधिक निर्भर होगी और आपके वातावरण में और क्या चल रहा है। यह भी ध्यान दें कि, SQLQueryStress का उपयोग करते समय स्कीमा स्थानांतरण परीक्षणों के लिए कोई अपवाद नहीं थे, आप उपभोग करने वाले एप्लिकेशन के आधार पर कुछ और सख्त टाइमआउट हिट कर सकते हैं। और यह औसतन इतना धीमा था, क्योंकि अवरोधन अधिक आक्रामक रूप से ढेर हो गया। कोई भी कभी भी अपवाद नहीं चाहता है, लेकिन जब इस तरह से कोई समझौता होता है, तो आप हर समय लंबे समय तक प्रतीक्षा करने वाले सभी लोगों की तुलना में यहां और वहां (रीफ्रेश ऑपरेशन की आवृत्ति के आधार पर) कुछ अपवादों को प्राथमिकता दे सकते हैं।
विभाजन स्विचिंग बनाम नाम बदलें/स्कीमा स्थानांतरण SQL सर्वर तालिका को ताज़ा करने के लिए
विभाजन स्विचिंग आपको यह चुनने की अनुमति देता है कि आपकी प्रक्रिया का कौन सा भाग समवर्ती की लागत वहन करता है। आप स्विचिंग प्रक्रिया को प्राथमिकता दे सकते हैं, इसलिए डेटा अधिक विश्वसनीय रूप से ताज़ा है, लेकिन इसका मतलब है कि आपके कुछ प्रश्न विफल हो जाएंगे। इसके विपरीत, आप धीमी रीफ्रेश प्रक्रिया (और वहां कभी-कभार विफलता) की कीमत पर प्रश्नों को प्राथमिकता दे सकते हैं। मुख्य जोर SQL सर्वर विभाजन स्विचिंग है जो लगभग सभी बिंदुओं पर पिछले नाम / स्कीमा स्थानांतरण तकनीकों की तुलना में SQL सर्वर तालिकाओं को ताज़ा करने के लिए एक बेहतर तरीका है, और आप मीठे स्थान पर उतरने के लिए अधिक मजबूत पुनर्प्रयास तर्क या अवधि सहिष्णुता के साथ प्रयोग कर सकते हैं। आपके कार्यभार के लिए।