इस महीने के टी-एसक्यूएल मंगलवार को माइक फाल (ब्लॉग | ट्विटर) द्वारा होस्ट किया जा रहा है, और विषय ट्रिक शॉट्स है, जहां हमें समुदाय को कुछ समाधान के बारे में बताने के लिए आमंत्रित किया जाता है जो हमने SQL सर्वर में उपयोग किया था, जो कम से कम हमें लगा, "ट्रिक शॉट" के एक प्रकार के रूप में - बिलियर्ड्स या स्नूकर में मास, "इंग्लिश" या जटिल बैंक शॉट्स का उपयोग करने के समान कुछ। कुछ 15 वर्षों तक SQL सर्वर के साथ काम करने के बाद, मुझे कुछ बहुत ही रोचक समस्याओं को हल करने के लिए ट्रिक्स के साथ आने का अवसर मिला है, लेकिन जो काफी पुन:प्रयोज्य प्रतीत होता है, आसानी से कई स्थितियों के अनुकूल होता है, और कार्यान्वित करने में आसान होता है, वह है जिसे मैं "स्कीमा स्विच-ए-रू" कहता हूं।
मान लें कि आपके पास एक परिदृश्य है जहां आपके पास एक बड़ी लुकअप तालिका है जिसे समय-समय पर ताज़ा करने की आवश्यकता होती है। इस लुकअप तालिका की कई सर्वरों पर आवश्यकता होती है और इसमें डेटा हो सकता है जो बाहरी या तृतीय पक्ष स्रोत से पॉप्युलेट हो जाता है, उदा। IP या डोमेन डेटा, या आपके अपने परिवेश के डेटा का प्रतिनिधित्व कर सकता है।
पहले दो परिदृश्य जहां मुझे इसके लिए एक समाधान की आवश्यकता थी, मेटाडेटा और डीनोर्मलाइज्ड डेटा को केवल-पढ़ने के लिए "डेटा कैश" के लिए उपलब्ध करा रहे थे - वास्तव में केवल SQL सर्वर MSDE (और बाद में एक्सप्रेस) विभिन्न वेब सर्वरों पर स्थापित इंस्टेंसेस, इसलिए वेब सर्वर खींच लिया यह प्राथमिक OLTP सिस्टम को परेशान करने के बजाय स्थानीय रूप से कैश्ड डेटा। यह बेमानी लग सकता है, लेकिन प्राथमिक ओएलटीपी प्रणाली से दूर पढ़ने की गतिविधि को ऑफ-लोड करना, और नेटवर्क कनेक्शन को पूरी तरह से समीकरण से बाहर निकालने में सक्षम होने के कारण, समग्र प्रदर्शन में एक वास्तविक टक्कर हुई और, विशेष रूप से, अंतिम उपयोगकर्ताओं के लिए ।
इन सर्वरों को डेटा की अद्यतन प्रतियों की आवश्यकता नहीं थी; वास्तव में, बहुत सी कैश टेबल केवल दैनिक रूप से अपडेट की जाती थीं। लेकिन चूंकि सिस्टम 24×7 थे, और इनमें से कुछ अपडेट में कई मिनट लग सकते थे, वे अक्सर वास्तविक ग्राहकों के सिस्टम पर वास्तविक काम करने के रास्ते में आ जाते थे।
मूल दृष्टिकोण(ओं)
बहुत शुरुआत में, कोड काफी सरल था:हमने उन पंक्तियों को हटा दिया जिन्हें स्रोत से हटा दिया गया था, उन सभी पंक्तियों को अपडेट किया जो हम बता सकते थे कि बदल गई हैं, और सभी नई पंक्तियों को सम्मिलित किया है। यह कुछ इस तरह दिखता था (संक्षिप्तता के लिए त्रुटि प्रबंधन आदि हटा दिया गया):
BEGIN TRANSACTION; DELETE dbo.Lookup WHERE [key] NOT IN (SELECT [key] FROM [source]); UPDATE d SET [col] = s.[col] FROM dbo.Lookup AS d INNER JOIN [source] AS s ON d.[key] = s.[key] -- AND [condition to detect change]; INSERT dbo.Lookup([cols]) SELECT [cols] FROM [source] WHERE [key] NOT IN (SELECT [key] FROM dbo.Lookup); COMMIT TRANSACTION;
कहने की जरूरत नहीं है कि जब सिस्टम उपयोग में था तो यह लेनदेन कुछ वास्तविक प्रदर्शन समस्याओं का कारण बन सकता है। निश्चित रूप से ऐसा करने के अन्य तरीके भी थे, लेकिन हमने जो भी तरीका आजमाया वह उतना ही धीमा और महंगा था। कितना धीमा और महंगा? "मुझे स्कैन गिनने दें..."
चूंकि यह पूर्व-दिनांकित MERGE, और हमने पहले से ही DTS जैसे "बाहरी" दृष्टिकोणों को त्याग दिया था, कुछ परीक्षणों के माध्यम से हमने निर्धारित किया कि यह केवल तालिका को पोंछने और इसे फिर से पॉप्युलेट करने के लिए अधिक कुशल होगा, बजाय कोशिश करने और स्रोत को सिंक करने के लिए। :
BEGIN TRANSACTION; TRUNCATE TABLE dbo.Lookup; INSERT dbo.Lookup([cols]) SELECT [cols] FROM [source]; COMMIT TRANSACTION;
अब, जैसा कि मैंने समझाया, [स्रोत] से इस क्वेरी में कुछ मिनट लग सकते हैं, खासकर यदि सभी वेब सर्वर समानांतर में अपडेट किए जा रहे थे (हमने जहां संभव हो वहां डगमगाने की कोशिश की)। और यदि कोई ग्राहक साइट पर था और लुकअप तालिका से संबंधित कोई क्वेरी चलाने का प्रयास कर रहा था, तो उन्हें उस लेन-देन के समाप्त होने की प्रतीक्षा करनी पड़ी। ज्यादातर मामलों में, अगर वे इस क्वेरी को आधी रात को चला रहे हैं, तो इससे कोई फर्क नहीं पड़ेगा कि उन्हें लुकअप डेटा की कल की कॉपी मिली है या आज की; इसलिए, उन्हें ताज़ा करने के लिए प्रतीक्षा करना मूर्खतापूर्ण लग रहा था, और वास्तव में कई समर्थन कॉलों का कारण बना।
तो जबकि यह बेहतर था, यह निश्चित रूप से परिपूर्ण से बहुत दूर था।
मेरा प्रारंभिक समाधान:sp_rename
मेरा प्रारंभिक समाधान, वापस जब SQL Server 2000 अच्छा था, एक "छाया" तालिका बनाना था:
CREATE TABLE dbo.Lookup_Shadow([cols]);
इस तरह मैं उपयोगकर्ताओं को बाधित किए बिना छाया तालिका को पॉप्युलेट कर सकता था, और फिर तीन-तरफा नाम बदल सकता था - एक तेज़, मेटाडेटा-केवल ऑपरेशन - केवल जनसंख्या पूर्ण होने के बाद। कुछ इस तरह (फिर से, पूरी तरह से सरलीकृत):
TRUNCATE TABLE dbo.Lookup_Shadow; INSERT dbo.Lookup_Shadow([cols]) SELECT [cols] FROM [source]; BEGIN TRANSACTION; EXEC sp_rename N'dbo.Lookup', N'dbo.Lookup_Fake'; EXEC sp_rename N'dbo.Lookup_Shadow', N'dbo.Lookup'; COMMIT TRANSACTION; -- if successful: EXEC sp_rename N'dbo.Lookup_Fake', N'dbo.Lookup_Shadow';
इस प्रारंभिक दृष्टिकोण का नकारात्मक पक्ष यह था कि sp_rename में एक गैर-दबाने योग्य आउटपुट संदेश है जो आपको वस्तुओं का नाम बदलने के खतरों के बारे में चेतावनी देता है। हमारे मामले में हमने SQL सर्वर एजेंट नौकरियों के माध्यम से यह कार्य किया, और हमने बहुत सारे मेटाडेटा और अन्य कैश टेबल को संभाला, इसलिए नौकरी का इतिहास इन सभी बेकार संदेशों से भर गया था और वास्तव में इतिहास के विवरण से वास्तविक त्रुटियों को काट दिया गया था। (मैंने 2007 में इसके बारे में शिकायत की थी, लेकिन मेरे सुझाव को अंततः खारिज कर दिया गया और "वोंट फिक्स" के रूप में बंद कर दिया गया।)
एक बेहतर समाधान :स्कीमा
एक बार जब हम SQL सर्वर 2005 में अपग्रेड हो गए, तो मैंने इस शानदार कमांड की खोज की, जिसे CREATE SCHEMA कहा जाता है। तालिकाओं का नाम बदलने के बजाय स्कीमा का उपयोग करके एक ही प्रकार के समाधान को लागू करना तुच्छ था, और अब एजेंट इतिहास इन सभी अनुपयोगी संदेशों से प्रदूषित नहीं होगा। मूल रूप से मैंने दो नए स्कीमा बनाए:
CREATE SCHEMA fake AUTHORIZATION dbo; CREATE SCHEMA shadow AUTHORIZATION dbo;
फिर मैंने लुकअप_शैडो तालिका को कैशे स्कीमा में स्थानांतरित कर दिया, और इसका नाम बदल दिया:
ALTER SCHEMA shadow TRANSFER dbo.Lookup_Shadow; EXEC sp_rename N'shadow.Lookup_Shadow', N'Lookup';
(यदि आप केवल इस समाधान को लागू कर रहे हैं, तो आप स्कीमा में तालिका की एक नई प्रतिलिपि बना रहे होंगे, मौजूदा तालिका को वहां नहीं ले जा रहे होंगे और उसका नाम बदल देंगे।)
उन दो स्कीमाओं के साथ, और छाया स्कीमा में लुकअप तालिका की एक प्रति के साथ, मेरा तीन-तरफ़ा नाम तीन-तरफ़ा स्कीमा स्थानांतरण बन गया:
TRUNCATE TABLE shadow.Lookup; INSERT shadow.Lookup([cols]) SELECT [cols] FROM [source]; -- perhaps an explicit statistics update here BEGIN TRANSACTION; ALTER SCHEMA fake TRANSFER dbo.Lookup; ALTER SCHEMA dbo TRANSFER shadow.Lookup; COMMIT TRANSACTION; ALTER SCHEMA shadow TRANSFER fake.Lookup;
इस बिंदु पर आप निश्चित रूप से तालिका की छाया प्रति खाली कर सकते हैं, हालांकि कुछ मामलों में मैंने समस्या निवारण उद्देश्यों के लिए डेटा की "पुरानी" प्रतिलिपि को छोड़ना उपयोगी पाया:
TRUNCATE TABLE shadow.Lookup;
शैडो कॉपी के साथ आप जो कुछ भी आगे करते हैं, आप यह सुनिश्चित करना चाहेंगे कि आप लेन-देन के बाहर करते हैं - दो स्थानांतरण संचालन यथासंभव संक्षिप्त और त्वरित होने चाहिए।
कुछ चेतावनी
- Foreign Keys
यदि लुकअप तालिका को विदेशी कुंजियों द्वारा संदर्भित किया जाता है तो यह बिल्कुल अलग तरीके से काम नहीं करेगा। हमारे मामले में हमने इन कैश टेबल पर कोई बाधा नहीं बताई, लेकिन यदि आप ऐसा करते हैं, तो आपको MERGE जैसे घुसपैठ के तरीकों से चिपके रहना पड़ सकता है। या केवल परिशिष्ट विधियों का उपयोग करें और कोई भी डेटा संशोधन करने से पहले विदेशी कुंजियों को अक्षम या छोड़ दें (फिर बाद में उन्हें फिर से बनाएं या पुनः सक्षम करें)। यदि आप MERGE / UPSERT तकनीकों से चिपके रहते हैं और आप इसे सर्वरों के बीच कर रहे हैं या, इससे भी बदतर, दूरस्थ सिस्टम से, मैं सर्वर के बीच इन विधियों का उपयोग करने की कोशिश करने के बजाय स्थानीय रूप से अपरिष्कृत डेटा प्राप्त करने की अत्यधिक अनुशंसा करता हूं।
ली> - आंकड़े
तालिकाओं को बदलने (नाम बदलें या स्कीमा स्थानांतरण का उपयोग करके) से तालिका की दो प्रतियों के बीच आंकड़े आगे-पीछे होंगे, और यह स्पष्ट रूप से योजनाओं के लिए एक मुद्दा हो सकता है। इसलिए आप इस प्रक्रिया के हिस्से के रूप में स्पष्ट आंकड़े अपडेट जोड़ने पर विचार कर सकते हैं।
- अन्य तरीके
निश्चित रूप से ऐसा करने के और भी तरीके हैं जिन्हें मुझे आजमाने का अवसर ही नहीं मिला। विभाजन स्विचिंग और एक दृश्य + पर्यायवाची का उपयोग दो दृष्टिकोण हैं जिनकी मैं भविष्य में विषय के अधिक गहन उपचार के लिए जांच कर सकता हूं। मुझे आपके अनुभव जानने में दिलचस्पी होगी और आपने अपने परिवेश में इस समस्या को कैसे हल किया है। और हाँ, मुझे एहसास है कि यह समस्या काफी हद तक उपलब्धता समूहों और SQL सर्वर 2012 में पढ़ने योग्य सेकेंडरी द्वारा हल की गई है, लेकिन मैं इसे "ट्रिक शॉट" मानता हूं यदि आप समस्या पर उच्च-अंत लाइसेंस फेंके बिना समस्या का समाधान कर सकते हैं, या एक की नकल कर सकते हैं कुछ तालिकाओं को बेमानी बनाने के लिए संपूर्ण डेटाबेस। :-)
निष्कर्ष
यदि आप यहां की सीमाओं के साथ रह सकते हैं, तो यह दृष्टिकोण उस परिदृश्य से बेहतर प्रदर्शनकर्ता हो सकता है जहां आप अनिवार्य रूप से एसएसआईएस या अपनी मर्ज/यूपीएसईआरटी दिनचर्या का उपयोग करके ऑफ़लाइन तालिका लेते हैं, लेकिन कृपया दोनों तकनीकों का परीक्षण करना सुनिश्चित करें। सबसे महत्वपूर्ण बात यह है कि तालिका तक पहुंचने वाले अंतिम उपयोगकर्ता को दिन के किसी भी समय ठीक वैसा ही अनुभव होना चाहिए, भले ही वे आपके आवधिक अपडेट के बीच में तालिका में आए हों।