मैं SQL सर्वर BULK INSERT
कमांड का उपयोग करते हुए कुछ पुराने कोड को फिर से लिखना चाहता हूं क्योंकि स्कीमा बदल गया है, और यह मेरे लिए हुआ है कि शायद मुझे इसके बजाय एक टीवीपी के साथ संग्रहीत प्रक्रिया पर स्विच करने के बारे में सोचना चाहिए, लेकिन मैं सोच रहा हूं कि क्या प्रभाव है यह प्रदर्शन पर हो सकता है।
कुछ पृष्ठभूमि की जानकारी जो यह बताने में मदद कर सकती है कि मैं यह प्रश्न क्यों पूछ रहा हूं:
डेटा वास्तव में एक वेब सेवा के माध्यम से आता है। वेब सेवा डेटाबेस सर्वर पर एक साझा फ़ोल्डर में एक पाठ फ़ाइल लिखती है जो बदले में एक कार्य करती है
BULK INSERT
। यह प्रक्रिया मूल रूप से SQL Server 2000 पर लागू की गई थी, और उस समयINSERT
सर्वर पर कुछ सौ बयानों को चकित करने के अलावा वास्तव में कोई विकल्प नहीं था , जो वास्तव में मूल प्रक्रिया थी और एक प्रदर्शन आपदा थी।डेटा को एक स्थायी मंचन तालिका में डाला जाता है और फिर एक बहुत बड़ी तालिका में विलय कर दिया जाता है (जिसके बाद इसे मंचन तालिका से हटा दिया जाता है)।
सम्मिलित करने के लिए डेटा की मात्रा "बड़ी" है, लेकिन "विशाल" नहीं है - आमतौर पर कुछ सौ पंक्तियां, शायद दुर्लभ साधनों में 5-10k पंक्तियां सबसे ऊपर हैं। इसलिए मेरी आंत की भावना यह है कि
BULK INSERT
एक गैर-लॉग ऑपरेशन होने से वह बड़ा नहीं होगा (लेकिन निश्चित रूप से मुझे यकीन नहीं है, इसलिए सवाल)।सम्मिलन वास्तव में एक बहुत बड़ी पाइपलाइन प्रक्रिया का हिस्सा है और उत्तराधिकार में कई बार होने की आवश्यकता होती है; इसलिए प्रदर्शन है महत्वपूर्ण।
जिन कारणों को मैं BULK INSERT
टीवीपी के साथ बदलना चाहूंगा वे हैं:
NetBIOS पर टेक्स्ट फ़ाइल लिखना संभवतः पहले से ही कुछ समय का खर्च है, और यह एक वास्तुशिल्प दृष्टिकोण से बहुत भीषण है।
मेरा मानना है कि स्टेजिंग टेबल (और) को समाप्त किया जाना चाहिए। इसका मुख्य कारण यह है कि सम्मिलित किए गए डेटा को प्रविष्टि के एक ही समय में कुछ अन्य अपडेट के लिए उपयोग करने की आवश्यकता है, और बड़े पैमाने पर उत्पादन तालिका से अपडेट का प्रयास करने की तुलना में यह लगभग महंगा है क्योंकि यह लगभग-खाली मंचन का उपयोग करने के लिए है तालिका। एक टीवीपी के साथ, पैरामीटर मूल रूप से स्टेजिंग टेबल है, मैं मुख्य प्रविष्टि से पहले / बाद में इसके साथ कुछ भी कर सकता हूं।
मैं बहुत अधिक डुप-चेकिंग, क्लीनअप कोड और थोक आवेषण के साथ जुड़े ओवरहेड के साथ बहुत कुछ कर सकता था।
स्टेजिंग टेबल या टेम्पर्डब पर लॉक कंटेस्टेंट के बारे में चिंता करने की कोई ज़रूरत नहीं है अगर सर्वर को एक ही बार में इनमें से कुछ ट्रांजैक्शन मिलते हैं (हम इसे टालने की कोशिश करते हैं, लेकिन ऐसा होता है)।
मैं स्पष्ट रूप से उत्पादन में कुछ भी डालने से पहले इसे प्रोफाइल करने जा रहा हूं, लेकिन मैंने सोचा कि यह एक अच्छा विचार हो सकता है कि इससे पहले कि मैं वह सारा समय बिताऊं, इससे पहले कि कोई भी इस उद्देश्य के लिए टीवीपी का उपयोग करने के बारे में कोई सख्त चेतावनी दे।
तो - किसी के लिए जो SQL Server 2008 के साथ पर्याप्त आरामदायक है या कम से कम इसकी जांच करने की कोशिश की है, क्या फैसला है? आवेषण के लिए, मान लें कि कुछ सौ से कुछ हज़ार पंक्तियों में, काफी हद तक लगातार हो रहा है, क्या टीवीपी सरसों को काटते हैं? क्या थोक आवेषण की तुलना में प्रदर्शन में महत्वपूर्ण अंतर है?
अद्यतन: अब 92% कम प्रश्नवाचक चिन्ह के साथ!
(AKA: परीक्षा परिणाम)
36-चरण परिनियोजन प्रक्रिया की तरह महसूस करने के बाद अंतिम परिणाम अब उत्पादन में है। दोनों समाधानों का बड़े पैमाने पर परीक्षण किया गया:
- साझा-फ़ोल्डर कोड को रिप करना और
SqlBulkCopy
सीधे वर्ग का उपयोग करना ; - TVPs के साथ एक संग्रहीत कार्यविधि पर स्विच करना।
बस इसलिए पाठकों को इस बात का अंदाजा हो सकता है कि वास्तव में क्या परीक्षण किया गया था, इस डेटा की विश्वसनीयता के रूप में किसी भी संदेह को दूर करने के लिए, यहां यह अधिक विस्तृत विवरण है कि यह आयात प्रक्रिया वास्तव में क्या करती है :
एक अस्थायी डेटा अनुक्रम के साथ शुरू करें जो सामान्य रूप से लगभग 20-50 डेटा बिंदु हैं (हालांकि यह कभी-कभी कुछ सौ तक हो सकता है);
उस पर पागल प्रसंस्करण का एक पूरा गुच्छा करो जो ज्यादातर डेटाबेस से स्वतंत्र है। इस प्रक्रिया को समानांतर किया जाता है, इसलिए एक ही समय में (1) में से लगभग 8-10 अनुक्रमों को संसाधित किया जा रहा है। प्रत्येक समानांतर प्रक्रिया 3 अतिरिक्त अनुक्रम उत्पन्न करती है।
सभी 3 अनुक्रम और मूल अनुक्रम लें और उन्हें एक बैच में संयोजित करें।
एक बड़े सुपर-बैच में सभी 8-10 अब समाप्त प्रसंस्करण कार्यों से बैचों को मिलाएं।
इसे या तो
BULK INSERT
रणनीति (अगला चरण देखें), या टीवीपी रणनीति (चरण 8 पर छोड़ें) का उपयोग करके आयात करें ।SqlBulkCopy
पूरे सुपर-बैच को 4 स्थायी मेज़िंग टेबल में डंप करने के लिए कक्षा का उपयोग करें ।एक संग्रहीत प्रक्रिया चलाएं कि (ए) तालिका के 2 पर एकत्रीकरण चरणों का एक गुच्छा करता है, जिसमें कई
JOIN
स्थितियां शामिल हैं, और फिर (बी)MERGE
कुल और गैर-एकत्रित डेटा दोनों का उपयोग करके 6 उत्पादन तालिकाओं पर प्रदर्शन करता है । (ख़त्म होना)या
DataTable
मर्ज किए जाने वाले डेटा वाले 4 ऑब्जेक्ट उत्पन्न करें ; उनमें से 3 में CLR प्रकार होते हैं जो दुर्भाग्य से ADO.NET TVPs द्वारा ठीक से समर्थित नहीं होते हैं, इसलिए उन्हें स्ट्रिंग अभ्यावेदन के रूप में जाना जाता है, जो प्रदर्शन को थोड़ा नुकसान पहुंचाता है।टीवीएस को एक संग्रहीत प्रक्रिया में फ़ीड करें, जो अनिवार्य रूप से (7) के रूप में एक ही प्रसंस्करण करता है, लेकिन सीधे प्राप्त तालिकाओं के साथ। (ख़त्म होना)
परिणाम काफी करीब थे, लेकिन टीवीपी के दृष्टिकोण ने अंततः औसत पर बेहतर प्रदर्शन किया, तब भी जब डेटा एक छोटी राशि से 1000 पंक्तियों से अधिक था।
ध्यान दें कि यह आयात प्रक्रिया उत्तराधिकार में कई बार हजारों बार चलाई जाती है, इसलिए औसत समय प्राप्त करना बहुत आसान था, गिनती के कितने घंटे (हाँ, घंटे) यह सभी मर्जों को पूरा करने के लिए ले लिया।
मूल रूप से, एक औसत मर्ज को पूरा होने में लगभग 8 सेकंड लगते थे (सामान्य भार के तहत)। NetBIOS कीचड़ को हटाकर SqlBulkCopy
समय को घटाकर लगभग 7 सेकंड कर दिया गया। TVPs पर स्विच करने से समय प्रति बैच 5.2 सेकंड कम हो गया । यह एक प्रक्रिया के लिए थ्रूपुट में 35% सुधार है जिसका चल रहा समय घंटों में मापा जाता है - इसलिए बुरा बिल्कुल नहीं। यह भी ~ 25% से अधिक सुधार है SqlBulkCopy
।
मैं वास्तव में काफी आश्वस्त हूं कि सही सुधार इससे काफी अधिक था। परीक्षण के दौरान यह स्पष्ट हो गया कि अंतिम विलय अब महत्वपूर्ण मार्ग नहीं था; इसके बजाय, वेब सेवा जो सभी डेटा प्रोसेसिंग कर रही थी, आने वाले अनुरोधों की संख्या के तहत बकसुआ बनाना शुरू कर रही थी। न तो सीपीयू और न ही डेटाबेस I / O वास्तव में अधिकतम थे, और कोई महत्वपूर्ण लॉकिंग गतिविधि नहीं थी। कुछ मामलों में हम क्रमिक विलय के बीच कुछ निष्क्रिय सेकंड का अंतर देख रहे थे। उपयोग करते समय थोड़ा अंतर था, लेकिन बहुत छोटा (आधा सेकंड या ऐसा ही) SqlBulkCopy
। लेकिन मुझे लगता है कि एक और दिन के लिए एक कहानी बन जाएगी।
निष्कर्ष: टेबल-वैल्यूड पैरामीटर्स वास्तव में BULK INSERT
मध्य आकार के डेटा सेट पर संचालित होने वाले जटिल आयात + परिवर्तन प्रक्रियाओं के संचालन से बेहतर प्रदर्शन करते हैं ।
मैं एक दूसरे बिंदु को जोड़ना चाहता हूं, बस उन लोगों की ओर से किसी भी आशंका को स्वीकार करने के लिए जो प्रो-स्टैगिंग-टेबल हैं। एक तरह से, यह पूरी सेवा एक विशाल स्टेजिंग प्रक्रिया है। प्रक्रिया के प्रत्येक चरण भारी, लेखा परीक्षा तो हम नहीं करते है की जरूरत है कि क्यों कुछ विशेष मर्ज विफल निर्धारित करने के लिए (हालांकि व्यवहार में यह लगभग कभी नहीं होता है) एक मचान तालिका। हमें बस इतना करना है कि सेवा में एक डिबग ध्वज सेट किया जाए और यह डिबगर से टूट जाएगा या डेटाबेस के बजाय किसी फ़ाइल में अपना डेटा डंप कर देगा।
दूसरे शब्दों में, हमारे पास पहले से ही प्रक्रिया में पर्याप्त अंतर्दृष्टि है और एक मंचन की सुरक्षा की आवश्यकता नहीं है; एकमात्र कारण यह था कि पहले चरण में हमारे पास मंच था और उन सभी INSERT
और UPDATE
कथनों पर जोर देने से बचने के लिए जिन्हें हमें अन्यथा उपयोग करना होगा। मूल प्रक्रिया में, स्टेजिंग डेटा केवल एक दूसरे के अंशों के लिए स्टेजिंग टेबल में रहता था, इसलिए इसने रखरखाव / रखरखाव की शर्तों में कोई मूल्य नहीं जोड़ा।
यह भी ध्यान दें कि हमने हर एक ऑपरेशन को टीवीपी से बदला नहीं हैBULK INSERT
। कई ऑपरेशन जो बड़ी मात्रा में डेटा के साथ काम करते हैं और / या इसे अभी भी उपयोग किए जाने वाले डीबी पर फेंकने के अलावा डेटा के साथ कुछ विशेष करने की आवश्यकता नहीं है SqlBulkCopy
। मैं यह नहीं सुझाव दे रहा हूं कि टीवीपी एक प्रदर्शन रामबाण है, केवल यह कि वे SqlBulkCopy
इस विशिष्ट उदाहरण में सफल रहे जिसमें प्रारंभिक मंचन और अंतिम मर्ज के बीच कई परिवर्तन शामिल थे।
इसलिए यह अब आपके पास है। सबसे प्रासंगिक लिंक खोजने के लिए प्वाइंट टीटीओनी जाता है, लेकिन मैं अन्य प्रतिक्रियाओं की भी सराहना करता हूं। एक बार फिर धन्यवाद!