2010-01-27 23 views
65

मुझे SQL सर्वर के BULK INSERT कमांड का उपयोग करके कुछ पुराने कोड को फिर से लिखना होगा क्योंकि स्कीमा बदल गया है, और यह मेरे लिए हुआ है कि शायद मुझे स्विचिंग के बारे में सोचना चाहिए इसके बजाए एक टीवीपी के साथ संग्रहीत प्रक्रिया में, लेकिन मुझे आश्चर्य है कि प्रदर्शन पर इसका क्या प्रभाव हो सकता है।बीसीपी/बल्क इंसर्ट बनाम तालिका-मूल्यवान पैरामीटर्स का प्रदर्शन

कुछ पृष्ठभूमि जानकारी है कि समझाने मदद कर सकता है कारण है कि मैं इस सवाल पूछ रहा हूँ:

  • डेटा वास्तव में एक वेब सेवा के माध्यम से में आता है। वेब सेवा डेटाबेस सर्वर पर एक साझा फ़ोल्डर में एक टेक्स्ट फ़ाइल लिखती है जो बदले में BULK INSERT निष्पादित करती है। यह प्रक्रिया मूल रूप से SQL Server 2000 पर कार्यान्वित की गई थी, और उस समय सर्वर पर कुछ सौ INSERT कथनों को चकित करने के अलावा वास्तव में कोई विकल्प नहीं था, जो वास्तव में मूल प्रक्रिया थी और एक प्रदर्शन आपदा थी।

  • डेटा को स्थायी स्टेजिंग तालिका में थोक डाला जाता है और फिर एक बड़ी तालिका में विलय किया जाता है (जिसके बाद इसे स्टेजिंग तालिका से हटा दिया जाता है)।

  • डालने के लिए डेटा की मात्रा "बड़ी" है, लेकिन "विशाल" नहीं - आमतौर पर कुछ सौ पंक्तियां, शायद दुर्लभ उदाहरणों में 5-10k पंक्तियां शीर्ष पर होती हैं। इसलिए मेरा आंत महसूस यह है कि BULK INSERT गैर-लॉग इन ऑपरेशन होने से नहीं होगा बड़ा अंतर (लेकिन निश्चित रूप से मुझे यकीन नहीं है, इसलिए सवाल)।

  • सम्मिलन वास्तव में एक बहुत बड़ी पाइपलाइन वाली बैच प्रक्रिया का हिस्सा है और उत्तराधिकार में कई बार होने की आवश्यकता है; इसलिए प्रदर्शन महत्वपूर्ण है।

कारणों मैं एक TVP साथ BULK INSERT को प्रतिस्थापित करना चाहते हैं:

  • NetBIOS से अधिक पाठ फ़ाइल लेखन शायद पहले से ही कुछ समय की लागत है, और यह एक वास्तुशिल्प के नजरिए से बहुत भीषण है।

  • मेरा मानना ​​है कि स्टेजिंग तालिका समाप्त हो सकती है (और चाहिए)। इसका मुख्य कारण यह है कि सम्मिलित डेटा को सम्मिलन के एक ही समय में कुछ अन्य अपडेटों के लिए उपयोग करने की आवश्यकता है, और यह लगभग-खाली स्टेजिंग का उपयोग करने के बजाय बड़े उत्पादन तालिका से अद्यतन का प्रयास करने के लिए बहुत महंगा है तालिका। एक टीवीपी के साथ, पैरामीटर मूल रूप से स्टेजिंग टेबल है, मैं मुख्य डालने से पहले/बाद में कुछ भी कर सकता हूं।

  • मैं डुप्ली-चेकिंग, क्लीनअप कोड और थोक आवेषण से जुड़े सभी ओवरहेड से काफी कुछ कर सकता हूं।

  • स्टेजिंग टेबल या tempdb पर लॉक विवाद के बारे में चिंता करने की आवश्यकता नहीं है यदि सर्वर को इनमें से कुछ लेनदेन एक बार में मिलते हैं (हम इसे टालने का प्रयास करते हैं, लेकिन ऐसा होता है)।

मैं स्पष्ट रूप से उत्पादन में कुछ भी डालने से पहले इस प्रोफाइल लिए जा रहा हूँ, लेकिन मैंने सोचा कि यह एक अच्छा विचार पहले चारों ओर इससे पहले कि मैं यह सब समय खर्च करते हैं पूछने के लिए हो सकता है, अगर किसी को भी जारी करने के लिए किसी भी कड़ी चेतावनी है, यह देखने इस उद्देश्य के लिए टीवीपी का उपयोग करने के बारे में।

तो - किसी भी व्यक्ति के लिए जो SQL Server 2008 के साथ पर्याप्त आरामदायक है या कम से कम इसकी जांच करने के लिए, निर्णय क्या है?आवेषण के लिए, मान लीजिए, कुछ सौ से कुछ हज़ार पंक्तियां, जो लगातार आधार पर होती हैं, क्या टीवीपी सरसों काटते हैं? थोक आवेषण की तुलना में प्रदर्शन में कोई महत्वपूर्ण अंतर है?


अद्यतन: अब 9 2% कम प्रश्न चिह्न के साथ!

(उर्फ: परीक्षण के परिणाम)

अंतिम परिणाम क्या एक 36-चरण तैनाती प्रक्रिया की तरह लगता है के बाद उत्पादन में है। दोनों समाधानों का व्यापक परीक्षण किया गया:

  • साझा फ़ोल्डर कोड को बाहर निकालना और सीधे SqlBulkCopy कक्षा का उपयोग करना;
  • टीवीपी के साथ एक संग्रहीत प्रक्रिया में स्विचिंग।

बस इतना पाठकों की एक विचार क्या वास्तव में परीक्षण किया गया था प्राप्त कर सकते हैं, इस डेटा की विश्वसनीयता के बारे में कोई संदेह दूर करने के लिए, यहाँ क्या इस आयात प्रक्रिया वास्तव में करता है की एक अधिक विस्तृत विवरण है:

  1. सामान्य रूप से लगभग 20-50 डेटा पॉइंट्स (हालांकि यह कभी-कभी कुछ सौ हो सकता है) के साथ एक अस्थायी डेटा अनुक्रम के साथ प्रारंभ करें;

  2. उस पर पागल प्रसंस्करण का पूरा समूह करें जो ज्यादातर डेटाबेस से स्वतंत्र है। यह प्रक्रिया समानांतर है, इसलिए (1) में अनुक्रमों के लगभग 8-10 एक ही समय में संसाधित किए जा रहे हैं। प्रत्येक समांतर प्रक्रिया 3 अतिरिक्त अनुक्रम उत्पन्न करती है।

  3. सभी 3 अनुक्रमों और मूल अनुक्रम लें और उन्हें एक बैच में गठबंधन करें।

  4. सभी 8-10 अब-समाप्त प्रोसेसिंग कार्यों से बैच को एक बड़े सुपर-बैच में मिलाएं।

  5. BULK INSERT रणनीति (अगले चरण देखें), या टीवीपी रणनीति (चरण 8 पर छोड़ें) का उपयोग करके इसे आयात करें।

  6. पूरे सुपर-बैच को 4 स्थायी स्टेजिंग टेबल में डंप करने के लिए SqlBulkCopy कक्षा का उपयोग करें।

  7. चलाया जाने वाला एक संग्रहीत प्रक्रिया है कि (क) तालिकाओं के 2, कई JOIN की स्थिति, और सहित तो पर एकत्रीकरण कदम की एक गुच्छा करता है (ख) दोनों एकत्रित और गैर एकत्रित का उपयोग कर एक MERGE 6 पर उत्पादन टेबल करता है डेटा। (समाप्त)

    या

  8. उत्पन्न डेटा वाली 4 DataTable वस्तुओं मर्ज करने; उनमें से 3 में सीएलआर प्रकार होते हैं जो दुर्भाग्यवश एडीओ.NET टीवीपी द्वारा समर्थित नहीं होते हैं, इसलिए उन्हें स्ट्रिंग प्रस्तुतियों के रूप में स्थानांतरित किया जाना चाहिए, जो प्रदर्शन को थोड़ा सा नुकसान पहुंचाते हैं।

  9. टीवीएस को एक संग्रहीत प्रक्रिया में फ़ीड करें, जो अनिवार्य रूप से उसी प्रसंस्करण (7) के रूप में कार्य करता है, लेकिन सीधे प्राप्त तालिकाओं के साथ।(समाप्त)

परिणाम यथोचित करीब थे, लेकिन TVP दृष्टिकोण अंततः औसतन बेहतर प्रदर्शन किया, तब भी जब डेटा एक छोटी राशि से 1000 पंक्तियाँ पार हो गई।

ध्यान दें कि यह आयात प्रक्रिया उत्तराधिकार में कई बार कई बार चलती है, इसलिए यह गणना करके औसत समय प्राप्त करना बहुत आसान था कि यह सभी विलयों को समाप्त करने के लिए कितने घंटे (हाँ, घंटे) लगा।

मूल रूप से, औसत विलय को पूरा करने के लिए लगभग 8 सेकंड लगते थे (सामान्य लोड के तहत)। नेटबीओएसएस क्लोज को हटाने और SqlBulkCopy पर स्विच करने से समय लगभग 7 सेकंड तक कम हो गया। टीवीपी पर स्विच करने से समय 5.2 सेकंड प्रति बैच में कम हो गया। यह एक 35% सुधार एक प्रक्रिया के लिए थ्रूपुट में है जिसका चलने का समय घंटों में मापा जाता है - इसलिए बिल्कुल बुरा नहीं। यह SqlBulkCopy पर ~ 25% सुधार भी है।

मुझे वास्तव में काफी विश्वास है कि वास्तविक सुधार इस से काफी अधिक था। परीक्षण के दौरान यह स्पष्ट हो गया कि अंतिम विलय अब महत्वपूर्ण मार्ग नहीं था; इसके बजाए, वेब सेवा जो सभी डेटा प्रोसेसिंग कर रही थी, आने वाले अनुरोधों की संख्या के तहत बकल शुरू हो रही थी। न तो सीपीयू और न ही डेटाबेस I/O वास्तव में अधिकतम हो गया था, और कोई महत्वपूर्ण लॉकिंग गतिविधि नहीं थी। कुछ मामलों में हम लगातार विलय के बीच कुछ निष्क्रिय सेकंड का अंतर देख रहे थे। SqlBulkCopy का उपयोग करते समय थोड़ा सा अंतर था, लेकिन बहुत छोटा (आधे सेकेंड या तो)। लेकिन मुझे लगता है कि एक और दिन के लिए एक कहानी बन जाएगी।

निष्कर्ष: तालिका-मूल्यवान पैरामीटर वास्तव में जटिल आकार के लिए BULK INSERT संचालन से बेहतर प्रदर्शन करते हैं + मध्यम आकार के डेटा सेट पर चल रही प्रक्रियाओं को परिवर्तित करें।


मैं, एक अन्य बिंदु जोड़ने सिर्फ लोग समर्थक मचान-टेबल रहे हैं की ओर से किसी भी आशंका शांत करने करना चाहते हैं। एक तरह से, यह पूरी सेवा एक विशाल स्टेजिंग प्रक्रिया है। प्रक्रिया के प्रत्येक चरण पर अत्यधिक लेखापरीक्षा की जाती है, इसलिए को की आवश्यकता नहीं है यह निर्धारित करने के लिए कि कोई विशेष विलय विफल क्यों हुआ (हालांकि व्यवहार में यह लगभग कभी नहीं होता)। हमें बस इतना करना है कि सेवा में डीबग फ्लैग सेट करें और यह डीबगर को तोड़ देगा या डाटाबेस की बजाय फाइल को डंप करेगा।

दूसरे शब्दों में, हमारे पास पहले से ही प्रक्रिया में पर्याप्त अंतर्दृष्टि है और स्टेजिंग टेबल की सुरक्षा की आवश्यकता नहीं है; पहली जगह में स्टेजिंग टेबल रखने का एकमात्र कारण यह था कि INSERT और UPDATE बयानों पर थ्रैशिंग से बचने के लिए हमें अन्यथा उपयोग करना होगा। मूल प्रक्रिया में, स्टेजिंग डेटा केवल एक दूसरे के अंशों के लिए स्टेजिंग तालिका में रहता था, इसलिए इसमें रखरखाव/रखरखाव शर्तों में कोई मूल्य नहीं जोड़ा गया।

यह भी ध्यान दें कि हमारे पास टीवीपी के साथ प्रत्येक एकल BULK INSERT ऑपरेशन को प्रतिस्थापित नहीं किया गया है। कई परिचालन जो डेटा की बड़ी मात्रा से निपटते हैं और/या डीबी में फेंकने के अलावा अन्य डेटा के साथ कुछ विशेष करने की आवश्यकता नहीं है, फिर भी SqlBulkCopy का उपयोग करें। मैं यह सुझाव नहीं दे रहा हूं कि टीवीपी एक प्रदर्शन पैनसिया हैं, केवल वे इस विशिष्ट उदाहरण में SqlBulkCopy से अधिक सफल हुए हैं जिसमें प्रारंभिक स्टेजिंग और अंतिम विलय के बीच कई परिवर्तन शामिल हैं।

तो आपके पास यह है। सबसे प्रासंगिक लिंक खोजने के लिए प्वाइंट टीटीनी जाता है, लेकिन मैं अन्य प्रतिक्रियाओं की भी सराहना करता हूं। एक बार फिर धन्यवाद!

उत्तर

7

मुझे वास्तव में टीवीपी के साथ अनुभव नहीं है, हालांकि एमएसडीएन here में एक अच्छा प्रदर्शन तुलना चार्ट बनाम बल्क इंसर्ट है।

वे कहते हैं कि बल्क इंसर्ट की स्टार्टअप लागत अधिक है, लेकिन उसके बाद तेज है। रिमोट क्लाइंट परिदृश्य में वे लगभग 1000 पंक्तियों ("सरल" सर्वर तर्क के लिए) रेखा खींचते हैं। उनके विवरण से निर्णय लेते हुए मैं कहूंगा कि आपको टीवीपी का उपयोग करने के साथ ठीक होना चाहिए। प्रदर्शन हिट - यदि कोई है - शायद नगण्य है और वास्तुशिल्प लाभ बहुत अच्छे लगते हैं।

संपादित करें: एक तरफ नोट पर आप सर्वर-स्थानीय फ़ाइल से बच सकते हैं और अभी भी SqlBulkCopy ऑब्जेक्ट का उपयोग करके थोक प्रति का उपयोग कर सकते हैं। बस डेटाटेबल को पॉप्युलेट करें, और उसे "WriteToServer" में फ़ीड करें- SqlBulkCopy उदाहरण का तरीका। उपयोग करने में आसान, और बहुत तेज़।

+0

लिंक के लिए धन्यवाद, यह वास्तव में काफी उपयोगी है क्योंकि एमएस टीवीपी की सिफारिश करता है जब डेटा जटिल तर्क (जो करता है) खिलाता है और हमारे पास बैच आकार को डायल या डाउन करने की क्षमता भी है, इसलिए हम बहुत दूर नहीं जाते हैं 1k-पंक्ति दर्द बिंदु। इस पर आधारित, कम से कम कोशिश करने और देखने के लिए समय हो सकता है, भले ही यह बहुत धीमी हो। – Aaronaught

+0

हाँ लिंक दिलचस्प है।@Aaronaught - इस तरह की स्थितियों में, संभावित दृष्टिकोणों के प्रदर्शन की खोज और विश्लेषण करने के लिए हमेशा अच्छा होता है, इसलिए मुझे आपके निष्कर्ष सुनना होगा! – AdaTheDev

4

मुझे लगता है कि मैं अभी भी एक थोक सम्मिलित दृष्टिकोण के साथ रहूंगा। आप पाते हैं कि tempdb अभी भी एक उचित संख्या में पंक्तियों के साथ एक टीवीपी का उपयोग कर हिट हो जाता है। यह मेरी आंत महसूस कर रहा है, मैं नहीं कह सकता कि मैंने टीवीपी का उपयोग करने के प्रदर्शन का परीक्षण किया है (हालांकि मुझे अन्य इनपुट सुनने में दिलचस्पी है)

यदि आप .NET का उपयोग करते हैं तो आप उल्लेख नहीं करते हैं, लेकिन दृष्टिकोण मैंने पिछले समाधानों को अनुकूलित करने के लिए लिया है SqlBulkCopy कक्षा का उपयोग करके डेटा का थोक भार करना - आपको लोड करने से पहले फ़ाइल में डेटा लिखने की आवश्यकता नहीं है, बस SqlBulkCopy कक्षा (उदाहरण के लिए) डेटाटेबल दें - यही वह है डीबी में डेटा डालने का सबसे तेज़ तरीका। 5-10 के पंक्तियां ज्यादा नहीं हैं, मैंने इसका इस्तेमाल 750 के लिए पंक्तियों तक किया है। मुझे संदेह है कि सामान्य रूप से, कुछ सौ पंक्तियों के साथ यह एक टीवीपी का उपयोग करके एक बड़ा अंतर नहीं बनायेगा। लेकिन स्केलिंग आईएमएचओ सीमित होगी।

शायद SQL 2008 में नई MERGE कार्यक्षमता आपको लाभ पहुंचाएगी?

इसके अलावा, यदि आपकी मौजूदा स्टेजिंग तालिका एक ऐसी तालिका है जिसका उपयोग इस प्रक्रिया के प्रत्येक उदाहरण के लिए किया जाता है और आप विवाद आदि के बारे में चिंतित हैं, तो क्या आपने हर बार एक नया "अस्थायी" लेकिन भौतिक स्टेजिंग टेबल बनाने पर विचार किया है, फिर इसे समाप्त होने पर इसे छोड़ना?

नोट करें कि आप किसी भी इंडेक्स के बिना इसे पॉप्युलेट करके, इस स्टेजिंग तालिका में लोडिंग को अनुकूलित कर सकते हैं। फिर एक बार आबादी के बाद, उस बिंदु पर किसी भी आवश्यक इंडेक्स को जोड़ें (FILLFACTOR = 100 इष्टतम पढ़ने के प्रदर्शन के लिए, इस बिंदु पर इसे अपडेट नहीं किया जाएगा)।

+0

मैं नेट का उपयोग करते हैं, और इस प्रक्रिया 'पहले बन करने के लिए SqlBulkCopy' होता है और बस बदल नहीं किया गया है। इसके बारे में मुझे याद दिलाने के लिए धन्यवाद, यह पुनरीक्षण के लायक हो सकता है। 'मेर्ज' का भी पहले से ही व्यापक रूप से उपयोग किया जा रहा है, और अस्थायी तालिकाओं को एक बार पहले कोशिश की गई थी लेकिन धीमे और प्रबंधन के लिए और अधिक कठिन पाया गया। इनपुट के लिए धन्यवाद! – Aaronaught

1

स्टेजिंग टेबल अच्छे हैं! वास्तव में मैं इसे किसी अन्य तरीके से नहीं करना चाहूंगा। क्यूं कर? चूंकि डेटा आयात अप्रत्याशित रूप से बदल सकते हैं (और अक्सर उन तरीकों से जिन्हें आप पूर्ववत नहीं कर सकते हैं, जैसे कॉलम को अभी भी पहला नाम और अंतिम नाम कहा जाता था, लेकिन उदाहरण के लिए, अंतिम नाम कॉलम में पहला नाम डेटा था, उदाहरण के लिए, उदाहरण नहीं चुनने के लिए यादृच्छिक रूप से।) एक स्टेजिंग टेबल के साथ समस्या का पता लगाने में आसान है ताकि आप देख सकें कि आयात किए गए कॉलम में वास्तव में कौन सा डेटा था। मुझे लगता है कि जब आप मेमोरी टेबल में उपयोग करते हैं तो मुझे लगता है कि मुश्किल है। मैं बहुत से लोगों को जानता हूं जो मेरे जीवन के लिए आयात करते हैं और वे सभी स्टेजिंग टेबल का उपयोग करने की सलाह देते हैं। मुझे संदेह है कि इसके लिए एक कारण है।

आगे काम करने की प्रक्रिया में एक छोटी स्कीमा परिवर्तन को ठीक करना प्रक्रिया को फिर से डिजाइन करने से आसान और कम समय लेने वाला है। यदि यह काम कर रहा है और कोई भी इसे बदलने के लिए घंटों तक भुगतान करने को तैयार नहीं है, तो केवल स्कीमा परिवर्तन के कारण तय करने की आवश्यकता को ठीक करें। पूरी प्रक्रिया को बदलकर, आप मौजूदा, परीक्षण की गई कार्य प्रक्रिया में एक छोटा सा परिवर्तन करके कहीं अधिक संभावित नई बग पेश करते हैं।

और आप सभी डेटा क्लीनअप कार्यों के साथ कैसे दूर जा रहे हैं? आप उन्हें अलग-अलग कर रहे हैं, लेकिन उन्हें अभी भी करने की जरूरत है। फिर, जिस प्रक्रिया को आप वर्णन करते हैं उसे बदलना बहुत जोखिम भरा है।

व्यक्तिगत रूप से यह मुझे लगता है जैसे आप नए खिलौनों के साथ खेलने का मौका पाने के बजाय पुरानी तकनीकों का उपयोग करके नाराज हैं। आपके पास थोक प्रविष्टि के अलावा अन्य परिवर्तनों को बदलने के लिए कोई वास्तविक आधार नहीं है।

+20

एसक्यूएल 2008 लगभग 2 वर्षों तक रहा है और यह प्रक्रिया उम्र के आसपास रही है, और यह पहली बार है जब मैंने इसे * माना * बदल दिया है। अंत में snarky टिप्पणी वास्तव में आवश्यक था? – Aaronaught

3

@ टीटीनी के उत्तर में दिए गए लिंक के संबंध में वर्णित चार्ट संदर्भ में लिया जाना चाहिए। मुझे यकीन नहीं है कि उन सिफारिशों में कितना वास्तविक शोध हुआ (यह भी ध्यान रखें कि चार्ट केवल 2008 और 2008 R2 उस दस्तावेज़ के संस्करणों में उपलब्ध है)। Maximizing Throughput with TVP

मैं 2009 के बाद से TVPs उपयोग किया गया है और पाया है कम से कम मेरे अनुभव में, में सरल डालने के अलावा और कुछ के लिए है कि:

दूसरी ओर एसक्यूएल सर्वर ग्राहक सलाहकार टीम की ओर से इस श्वेतपत्र है बिना किसी अतिरिक्त तर्क की आवश्यकता वाले गंतव्य तालिका (जो शायद ही कभी मामला है), तो टीवीपी आमतौर पर बेहतर विकल्प होते हैं।

मैं स्टेजिंग टेबल से बचने के लिए होता हूं क्योंकि ऐप परत पर डेटा सत्यापन किया जाना चाहिए। टीवीपी का उपयोग करके, इसे आसानी से समायोजित किया जाता है और संग्रहीत प्रक्रिया में टीवीपी टेबल वैरिएबल अपनी प्रकृति, एक स्थानीय स्टेजिंग टेबल (इसलिए एक ही समय में चल रही अन्य प्रक्रियाओं के साथ कोई संघर्ष नहीं होता है जैसे स्टेजिंग के लिए वास्तविक तालिका का उपयोग करते समय)।

परीक्षण प्रश्न में किया के बारे में, मुझे लगता है कि यह और भी तेजी से क्या मूल रूप से मिला था होना दिखाया जा सकता है:

  1. आप एक DataTable का उपयोग नहीं किया जाना चाहिए, बाहर इसके लिए उपयोग करें जब तक आपके आवेदन है टीवीपी को मूल्य भेजने का। IEnumerable<SqlDataRecord> इंटरफ़ेस का उपयोग करना तेज़ है और कम स्मृति का उपयोग करता है क्योंकि आप इसे स्मृति में संग्रह को डुप्लिकेट नहीं कर रहे हैं केवल इसे डीबी को भेजने के लिए। मैं इस निम्नलिखित स्थानों में दर्ज किया है:
  2. टीवीपी टेबल वैरिएबल हैं और इस तरह आंकड़े बनाए नहीं रखते हैं। मतलब, वे क्वेरी ऑप्टिमाइज़र को केवल 1 पंक्ति की रिपोर्ट करते हैं। तो, अपने proc में, या तो:
    • उपयोग एक सरल चयन के अलावा और कुछ के लिए TVP का उपयोग कर किसी भी प्रश्न पर बयान स्तरीय recompile: OPTION (RECOMPILE)
    • एक स्थानीय अस्थायी तालिका बनाएं (यानी एकल #) और नकल सामग्री अस्थायी तालिका में TVP की