कार्यप्रणाली के संबंध में, मेरा मानना है कि आप गलत बी-पेड़ को छाल रहे हैं ;-)।
हम क्या जानते हैं:
सबसे पहले, आइए समेकित करें और समीक्षा करें कि हम स्थिति के बारे में क्या जानते हैं:
हम क्या कर सकते हैं:
अगला, हम इन सभी डेटा बिंदुओं को एक साथ देख सकते हैं कि क्या हम अतिरिक्त विवरणों को संश्लेषित कर सकते हैं जो हमें एक या एक से अधिक बोतल गर्दन खोजने में मदद करेंगे, और या तो एक समाधान की ओर इशारा करेंगे, या कम से कम कुछ संभव समाधानों का शासन करेंगे।
टिप्पणियों में विचार की वर्तमान दिशा यह है कि मुख्य मुद्दा SQL सर्वर और एक्सेल के बीच डेटा स्थानांतरण है। क्या वास्तव में मामला है? यदि संग्रहीत प्रक्रिया को 800,000 पंक्तियों में से प्रत्येक के लिए कहा जाता है और प्रत्येक कॉल (यानी प्रत्येक पंक्ति) के अनुसार 50 एमएस लेता है, जो 40,000 सेकंड (एमएस नहीं) को जोड़ता है। और वह 666 मिनट (hhmm; ;-), या सिर्फ 11 घंटे से अधिक) के बराबर है। फिर भी पूरी प्रक्रिया को चलाने में केवल 7 घंटे लगने की बात कही गई। हमारे पास कुल समय में पहले से ही 4 घंटे हैं, और हमने गणना करने या परिणामों को SQL सर्वर पर वापस करने के लिए समय भी जोड़ा है। इसलिए यहां कुछ ठीक नहीं है।
संग्रहीत प्रक्रिया की परिभाषा को देखते हुए, इसके लिए केवल एक इनपुट पैरामीटर है @FileID
; कोई फिल्टर नहीं है @RowID
। इसलिए मुझे संदेह है कि निम्नलिखित दो परिदृश्यों में से एक हो रहा है:
- यह संग्रहित प्रक्रिया वास्तव में प्रत्येक पंक्ति के अनुसार नहीं मिलती है, बल्कि प्रत्येक के अनुसार होती है
@FileID
, जो लगभग 4000 पंक्तियों में दिखाई देती है। यदि बताई गई 4000 पंक्तियाँ काफी सुसंगत राशि हैं, तो 800,000 पंक्तियों में समूह में से केवल 200 हैं। और 200 प्रत्येक 7 घंटे में केवल 10 सेकंड के लिए प्रत्येक मात्रा में 50 एमएस ले रहा है।
- यदि यह संग्रहित प्रक्रिया वास्तव में हर पंक्ति के लिए कहलाती है, तो पहली बार एक नया समय
@FileID
बीतने के बाद बफ़र पूल में नई पंक्तियों को खींचने में थोड़ा समय नहीं लगेगा, लेकिन फिर अगले 3999 में आम तौर पर पहले से ही होने के कारण तेजी से वापसी होगी। कैश्ड, है ना?
मुझे लगता है कि इस "फ़िल्टर" संग्रहित प्रक्रिया, या SQL सर्वर से एक्सेल में किसी भी डेटा स्थानांतरण पर ध्यान केंद्रित करना एक लाल हेरिंग है ।
फिलहाल, मुझे लगता है कि अभाव प्रदर्शन के सबसे प्रासंगिक संकेतक हैं:
- 800,000 पंक्तियाँ हैं
- ऑपरेशन एक समय में एक पंक्ति पर काम करता है
- डेटा को SQL सर्वर पर वापस सहेजा जा रहा है, इसलिए "[उपयोग करता है] कुछ कॉलमों से मानों को अन्य स्तंभों में हेरफेर करने के लिए " [मेरे चरण चरण;; ]]
मुझे संदेह है कि:
- जबकि डेटा पुनर्प्राप्ति और गणना में सुधार के लिए कुछ जगह है, जिससे उन बेहतर प्रसंस्करण समय में एक महत्वपूर्ण कमी की राशि नहीं होगी।
- प्रमुख अड़चन 800,000 अलग-अलग
UPDATE
बयान जारी कर रही है , जो 800,000 अलग-अलग लेनदेन है।
मेरी सिफारिश (वर्तमान में उपलब्ध जानकारी के आधार पर):
सुधार का आपका सबसे बड़ा क्षेत्र एक समय में कई पंक्तियों को अपडेट करना होगा (यानी एक लेनदेन में)। आपको प्रत्येक के FileID
बजाय प्रत्येक के संदर्भ में काम करने के लिए अपनी प्रक्रिया को अद्यतन करना चाहिए RowID
। इसलिए:
FileID
किसी सरणी में किसी विशेष की सभी 4000 पंक्तियों में पढ़ें
- सरणी में उन तत्वों का प्रतिनिधित्व होना चाहिए जिनमें फ़ील्ड में हेरफेर किया जा रहा है
- सरणी के माध्यम से चक्र, प्रत्येक पंक्ति को संसाधित करना जैसा कि आप वर्तमान में करते हैं
- एक बार सरणी में सभी पंक्तियों (अर्थात इस विशेष के लिए
FileID
) की गणना की गई है:
- लेन-देन शुरू करें
- प्रत्येक को प्रत्येक अद्यतन कॉल करें
RowID
- यदि कोई त्रुटि नहीं है, तो लेनदेन करें
- यदि कोई त्रुटि हुई है, तो रोलबैक और उचित रूप से संभालें
यदि आपका क्लस्टर्ड इंडेक्स पहले से परिभाषित नहीं है, (FileID, RowID)
तो आपको उस पर विचार करना चाहिए (जैसा कि @MikaelEriksson ने प्रश्न पर टिप्पणी में सुझाया है)। यह इन सिंगलटन UPDATE को मदद नहीं करेगा, लेकिन यह कम से कम समग्र संचालन में सुधार करेगा, जैसे कि आप उस "फ़िल्टर" संग्रहीत कार्यविधि में क्या कर रहे हैं क्योंकि वे सभी पर आधारित हैं FileID
।
आपको तर्क को संकलित भाषा में स्थानांतरित करने पर विचार करना चाहिए। मैं एक .NET WinForms ऐप या यहां तक कि कंसोल ऐप बनाने का सुझाव दूंगा। मैं कंसोल ऐप पसंद करता हूं क्योंकि यह एसक्यूएल एजेंट या विंडोज शेड्यूल्ड टास्क के जरिए शेड्यूल करना आसान है। इससे कोई फर्क नहीं पड़ता कि यह VB.NET या C # में किया गया है। VB.NET आपके डेवलपर के लिए अधिक प्राकृतिक फिट हो सकता है, लेकिन फिर भी कुछ सीखने की अवस्था होगी।
मुझे SQLCLR में जाने के लिए इस बिंदु पर कोई कारण नहीं दिखता है। यदि एल्गोरिथ्म बार-बार बदलता है, तो इससे हर समय असेंबली को फिर से तैनात करना होगा। कंसोल ऐप को फिर से बनाना और .exe को नेटवर्क पर उचित साझा फ़ोल्डर में रखा जाना चाहिए जैसे कि आप बस एक ही प्रोग्राम चलाते हैं और यह हमेशा अप-टू-डेट रहने के लिए होता है, ऐसा करने के लिए काफी आसान होना चाहिए।
मुझे नहीं लगता कि टी-एसक्यूएल में प्रसंस्करण को पूरी तरह से स्थानांतरित करने में मदद मिलेगी यदि समस्या मुझे संदेह है और आप एक समय में केवल एक अद्यतन कर रहे हैं।
यदि प्रोसेसिंग को .NET में ले जाया जाता है, तो आप टेबल-वेल्यूड पैरामीटर्स (टीवीपी) का उपयोग कर सकते हैं, ताकि आप ऐरे को एक संग्रहीत प्रक्रिया में पास करेंगे जो UPDATE
कि टीवीपी टेबल चर के लिए एक JOINs को कॉल करेगा और इसलिए यह एक एकल लेनदेन है । टीवीपी को 4000 INSERT
एस को एकल लेनदेन में वर्गीकृत करने से अधिक तेज़ होना चाहिए । लेकिन TVP INSERT
का 1 लेन-देन में 4000 s से अधिक के उपयोग से आने वाला लाभ उतने महत्वपूर्ण नहीं होगा जितना कि 800,000 अलग-अलग लेन-देन से 4000 पंक्तियों के प्रत्येक 200 लेन-देन पर जाने पर देखा गया सुधार।
TVP विकल्प VBA पक्ष के लिए मूल रूप से उपलब्ध नहीं है, लेकिन कोई व्यक्ति ऐसे काम के साथ आया है, जो परीक्षण के लायक हो सकता है:
VBA से SQL Server 2008 R2 में जाने पर मैं डेटाबेस प्रदर्शन को कैसे बेहतर करूँ?
यदि फ़िल्टर खरीद केवल क्लॉज FileID
में उपयोग की WHERE
जा रही है, और यदि उस खरीद को वास्तव में प्रति पंक्ति कहा जा रहा है, तो आप पहले रन के परिणामों को कैशिंग करके और बाकी पंक्तियों के लिए उनका उपयोग करके कुछ प्रसंस्करण समय बचा सकते हैं FileID
, सही?
एक बार जब आप फाइलआईडी के अनुसार प्रसंस्करण कर लेते हैं , तो हम समानांतर प्रसंस्करण के बारे में बात करना शुरू कर सकते हैं। लेकिन उस बिंदु पर यह आवश्यक नहीं हो सकता है :)। यह देखते हुए कि आप 3 काफी प्रमुख गैर-आदर्श भागों के साथ काम कर रहे हैं: एक्सेल, VBA और 800k लेन-देन, SSIS, या समानांतर चतुर्भुज की कोई भी बात, या जो जानता है-क्या है, समय से पहले का अनुकूलन / कार्ट-से-हॉर्स सामान है । यदि हम इस 7 घंटे की प्रक्रिया को 10 मिनट या उससे कम समय तक प्राप्त कर सकते हैं, तो क्या आप इसे तेजी से बनाने के लिए अतिरिक्त तरीके सोच रहे हैं? क्या कोई लक्ष्य पूरा होने का समय है जो आपके मन में है? ध्यान रखें कि एक बार प्रसंस्करण प्रति FileID पर किया जाता है आधार, यदि आपके पास VB.NET कंसोल ऐप (यानी कमांड-लाइन .EXE) है, तो आपको एक बार में उन कुछ फ़ाइलआईडी को चलाने से कुछ नहीं होगा :), चाहे SQL एजेंट CmdExec चरण या विंडोज शेड्यूल किए गए मास्क के माध्यम से। आदि।
और, आप हमेशा "चरणबद्ध" दृष्टिकोण अपना सकते हैं और एक बार में कुछ सुधार कर सकते हैं। जैसे कि प्रति अपडेट करना शुरू करना FileID
और इसलिए उस समूह के लिए एक लेनदेन का उपयोग करना। फिर, देखें कि क्या आप टीवीपी काम कर सकते हैं। फिर उस कोड को लेने और इसे VB.NET में ले जाने के बारे में देखें (और TVPs .NET में काम करते हैं इसलिए यह अच्छी तरह से पोर्ट करेगा)।
क्या हम नहीं जानते कि अभी भी मदद कर सकता है:
- क्या "फ़िल्टर" संग्रहीत कार्यविधि पंक्ति प्रति या फ़ाइल के अनुसार चलती है ? क्या हमारे पास उस संग्रहित प्रक्रिया की पूरी परिभाषा भी है?
- तालिका का पूर्ण स्कीमा। यह तालिका कितनी चौड़ी है? चर की लंबाई के कितने क्षेत्र हैं? कितने क्षेत्र NULLable हैं? यदि कोई भी NULLable है, तो कितने NULLs हैं?
- इस तालिका के लिए अनुक्रमणिका। क्या इसका विभाजन हुआ है? क्या ROW या PAGE कम्प्रेशन का उपयोग किया जा रहा है?
- MB / GB के संदर्भ में यह तालिका कितनी बड़ी है?
- इस तालिका के लिए सूचकांक रखरखाव कैसे संभाला जाता है? सूचकांक कितने खंडित हैं? आंकड़ों की तारीख कैसे अपडेट की जाती है?
- क्या कोई अन्य प्रक्रिया इस तालिका को लिखती है जबकि यह 7 घंटे की प्रक्रिया हो रही है? विवाद का संभावित स्रोत।
- क्या इस तालिका से कोई अन्य प्रक्रिया पढ़ी जाती है जबकि यह 7 घंटे की प्रक्रिया हो रही है? विवाद का संभावित स्रोत।
अद्यतन 1:
** VBA (विजुअल बेसिक फॉर एप्लिकेशन) और इसके साथ क्या किया जा सकता है, इस बारे में कुछ भ्रम प्रतीत होता है, इसलिए यह सुनिश्चित करने के लिए है कि हम सभी एक ही वेब-पेज पर हैं:
अद्यतन 2:
एक और बात पर विचार करें: कनेक्शन कैसे संभाले जा रहे हैं? क्या VBA कोड प्रत्येक ऑपरेशन के अनुसार कनेक्शन को खोलना और बंद करना है, या क्या यह प्रक्रिया की शुरुआत में कनेक्शन को खोलता है और प्रक्रिया के अंत में बंद कर देता है (अर्थात 7 घंटे बाद)? कनेक्शन पूलिंग के साथ भी (जो, डिफ़ॉल्ट रूप से, ADO के लिए सक्षम होना चाहिए), अभी भी खोलने और बंद करने के बीच काफी प्रभाव होना चाहिए, एक बार खोलने और बंद करने के विपरीत 800,200 या 1,600,000 बार। वे मान कम से कम 800,000 UPDATEs या तो 200 या 800k EXECs पर आधारित होते हैं (यह निर्भर करता है कि फ़िल्टर संग्रहीत प्रक्रिया वास्तव में कैसे निष्पादित की जा रही है)।
बहुत से कनेक्शन का यह मुद्दा स्वचालित रूप से ऊपर उल्लिखित सिफारिश से कम हो गया है। एक लेनदेन बनाकर और उस लेनदेन के भीतर सभी अद्यतन करने के बाद, आप उस कनेक्शन को खुला रखने वाले हैं और प्रत्येक के लिए पुन: उपयोग कर रहे हैं UPDATE
। निर्दिष्ट FileID
या प्रति 4000 पंक्तियों को प्राप्त करने के लिए प्रारंभिक कॉल से कनेक्शन को खुला रखा गया है या नहीं , या उसके बाद बंद हो गया "ऑपरेशन" और फिर से UPDATEs के लिए खोला गया, अब तक कम प्रभाव है क्योंकि अब हम दोनों के अंतर के बारे में बात कर रहे हैं पूरी प्रक्रिया में 200 या 400 कुल कनेक्शन।
अद्यतन 3:
मैंने कुछ त्वरित परीक्षण किया। कृपया ध्यान रखें कि यह एक छोटे पैमाने पर परीक्षण है, और सटीक एक ही ऑपरेशन नहीं है (शुद्ध INSERT बनाम EXEC + UPDATE)। हालांकि, कनेक्शन और लेन-देन को कैसे संभाला जाता है, इससे संबंधित समय में अंतर अभी भी प्रासंगिक है, इसलिए यहां अपेक्षाकृत समान प्रभाव रखने के लिए जानकारी को एक्सट्रपलेशन किया जा सकता है।
परीक्षण पैरामीटर:
- SQL सर्वर 2012 डेवलपर संस्करण (64-बिट), SP2
तालिका:
CREATE TABLE dbo.ManyInserts
(
RowID INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
InsertTime DATETIME NOT NULL DEFAULT (GETDATE()),
SomeValue BIGINT NULL
);
ऑपरेशन:
INSERT INTO dbo.ManyInserts (SomeValue) VALUES ({LoopIndex * 12});
- प्रत्येक परीक्षण में कुल आवेषण: 10,000
- प्रत्येक परीक्षण के अनुसार रीसेट:
TRUNCATE TABLE dbo.ManyInserts;
(इस परीक्षण की प्रकृति को देखते हुए, FREEPROCCACHE, FREESYSTEMCACHE और DROPCLEANBUFFERS बहुत अधिक मूल्य नहीं जोड़ते हैं।)
- रिकवरी मॉडल: SIMPLE (और लॉग फ़ाइल में शायद 1 जीबी मुफ्त)
- लेनदेन का उपयोग करने वाले टेस्ट केवल एक ही कनेक्शन का उपयोग करते हैं, भले ही कितने लेनदेन हों।
परिणाम:
Test Milliseconds
------- ------------
10k INSERTs across 10k Connections 3968 - 4163
10k INSERTs across 1 Connection 3466 - 3654
10k INSERTs across 1 Transaction 1074 - 1086
10k INSERTs across 10 Transactions 1095 - 1169
जैसा कि आप देख सकते हैं, भले ही डीबी के लिए एडीओ कनेक्शन पहले से ही सभी ऑपरेशनों में साझा किया जा रहा है, उन्हें एक स्पष्ट लेनदेन का उपयोग करके बैचों में समूहित करना (एडीओ ऑब्जेक्ट को इसे संभालने में सक्षम होना चाहिए) को महत्वपूर्ण रूप से गारंटी दी जाती है (यानी 2x सुधार पर) समग्र प्रक्रिया का समय कम करें।