2010-07-19 4 views
8

मैं एक .NET घटक पर काम कर रहा हूं जो डेटाबेस से डेटा का एक सेट प्राप्त करता है, डेटा के उस सेट पर कुछ व्यावसायिक तर्क करता है, और फिर संग्रहीत प्रक्रिया के माध्यम से डेटाबेस में एकल रिकॉर्ड अपडेट करता है जो spUpdateOrderDetailDiscountedItem जैसा कुछ दिखता है।डेटाबेस को अद्यतन करने के लिए 368 बार संग्रहीत प्रक्रिया को फायर करने का अच्छा विकल्प क्या है?

डेटा के छोटे सेट के लिए, यह एक समस्या नहीं है, लेकिन जब मैं डेटा की एक बहुत बड़ी सेट है कि डेटाबेस में रिकॉर्ड अपडेट करने के लिए कॉल 368 संग्रहीत proc के एक यात्रा के लिए आवश्यक था, मुझे एहसास हुआ कि मैं एक समस्या थी । एक वरिष्ठ देव ने मेरे संग्रहित प्रो कोड को देखा और कहा कि यह ठीक लग रहा है, लेकिन अब मैं डेटाबेस में "बैच" डेटा भेजने के लिए एक बेहतर तरीका तलाशना चाहता हूं।

बैच में डेटाबेस को अद्यतन करने के लिए मेरे पास कौन से विकल्प हैं? क्या यह संग्रहीत प्रोसेस के साथ संभव है? मेरे पास अन्य विकल्प क्या हैं?

मेरे पास एक पूर्ण ओआरएम स्थापित करने का विकल्प नहीं होगा, लेकिन किसी भी सलाह की सराहना की जाती है।


अतिरिक्त पृष्ठभूमि जानकारी:

हमारे वर्तमान डेटा का उपयोग मॉडल 5 साल पहले बनाया गया था और डाटाबेस के लिए सभी कॉल वर्तमान में ExecQuery और GetDataTable जैसे नामों के साथ मॉड्यूलर/स्थिर कार्यों के माध्यम से निष्पादित हो। मुझे यकीन नहीं है कि मैं उस मॉडल के भीतर रहने के लिए आवश्यक हूं, लेकिन मुझे डीबी में जाने के लिए हमारे वर्तमान डीएएल के बाहर जाने के लिए बहुत अच्छा औचित्य प्रदान करना होगा।

ध्यान देने योग्य भी है, जब सीआरयूडी संचालन और डेटाबेस की बात आती है तो मैं बिल्कुल नया हूं। मैं कोड के .NET पक्ष में खेलना/काम करना पसंद करता हूं, लेकिन डेटा को कहीं भी संग्रहीत किया जाना चाहिए, है ना?


संग्रहित प्रोक सामग्री:

ALTER PROCEDURE [dbo].[spUpdateOrderDetailDiscountedItem] 
    -- Add the parameters for the stored procedure here 
    @OrderDetailID decimal = 0, 
    @Discount money = 0, 
    @ExtPrice money = 0, 
    @LineDiscountTypeID int = 0, 
    @OrdersID decimal = 0, 
    @QuantityDiscounted money = 0, 
    @UpdateOrderHeader int = 0, 
    @PromoCode varchar(6) = '', 
    @TotalDiscount money = 0 

AS 
BEGIN 
    -- SET NOCOUNT ON added to prevent extra result sets from 
    -- interfering with SELECT statements. 
    SET NOCOUNT ON; 

    -- Insert statements for procedure here 
    Update OrderDetail 
    Set Discount = @Discount, ExtPrice = @ExtPrice, LineDiscountTypeID = @LineDiscountTypeID, LineDiscountPercent = @QuantityDiscounted 
    From OrderDetail with (nolock) 
    Where OrderDetailID = @OrderDetailID 

    if @UpdateOrderHeader = -1 
     Begin 
     --This code should get code the last time this query is executed, but only then. 
     exec spUpdateOrdersHeaderForSkuGroupSourceCode @OrdersID, 7, 0, @PromoCode, @TotalDiscount 
     End 
+8

368 संचालन बहुत कुछ नहीं है। – Fosco

+0

संग्रहीत प्रक्रिया सामग्री को देखने की आवश्यकता है, भले ही सार ... –

+2

लगभग सभी ओआरएम अभी भी 368 डेटाबेस कॉल करेंगे .. वे बस उन्हें बैच करते हैं। – NotMe

उत्तर

9

उपयोग में देखा गया एक आसान और वैकल्पिक तरीका एसक्यूएल_एक्सएक्स को स्ट्रिंग में पैरामीटर के साथ स्पोक को बुलाते हुए एक SQL कथन बनाना है। सुनिश्चित नहीं हैं कि इस या यदि आप ऐसा करते हैं तो कृपया उसे चुनें, StringBuilder का इस्तेमाल करें सलाह दी है, तो नहीं है, लेकिन नेट के नजरिए से, आप केवल एक SqlCommand को आबाद करने और एक बार ExecuteNonQuery बुला रहे हैं ...

नोट! :-)

अद्यतन: मैं बहुत क्रिस जीवंत के जवाब पसंद करते हैं, अब तक तालिका-मान पैरामीटर ... दुर्भाग्य से ओपी 2005

+0

यह शायद कम से कम आक्रामक समाधान है। +1 – Chris

+0

@ क्रिस मैंने देखा कि यह कोड से तुलनात्मक रूप से स्पष्ट रूप से कई डेटाबेस कमांडों को बैच करने के लिए उपयोग किया जाता है - आपको अभी भी स्पॉक्स के लाभ मिलते हैं, लेकिन स्ट्रिंग में पैरामीटर को मान्य तरीके से एन्कोड करने के लिए आपको थोड़ा अतिरिक्त तर्क चाहिए। मेरा पसंदीदा मार्ग नहीं, लेकिन समझ में आता है। –

+1

ऐसा नहीं लगता कि आपको पैरामीटरयुक्त प्रश्नों के बारे में चिंता करने की आवश्यकता है यदि आप जो कुछ भी कर रहे हैं वह प्रोसेस को कॉल कर रहा है क्योंकि उनके पास अपनी स्वयं की क्वेरी योजना है? –

3

आप संग्रहीत प्रक्रिया करने के लिए XML इनपुट के रूप में डेटा का पूरा सेट भेज सकते हैं। फिर आप डेटाबेस को संशोधित करने के लिए सेट ऑपरेशंस कर सकते हैं। सेट आधारित आरबीएआर को लगभग हर बार प्रदर्शन पर हरा देगा।

+0

उत्तर के लिए धन्यवाद। आरबीएआर क्या है? –

+0

@ बेन: पंक्ति को agonizing द्वारा पंक्ति। –

+0

हा। हाँ, पूरी तरह से स्थिति को बताता है। –

0

उपयोग कर रहा है के बारे में पता नहीं था आप 368 के साथ बयान batched बना सकते हैं आपकी proc को कॉल करता है, तो कम से कम आपके पास 368 राउंड ट्रिप नहीं होंगे। यानी छद्म कोड

var lotsOfCommands = "spUpdateOrderDetailDiscountedItem 1; spUpdateOrderDetailDiscountedItem 2;spUpdateOrderDetailDiscountedItem ... 368' 

var new sqlcommand(lotsOfCommands) 
command.CommandType = CommandType.Text; 

//execute command 
+0

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

+0

अच्छा, मुझे खेद है, लेकिन क्या आप वास्तव में सोचते हैं कि 368 राउंड ट्रिप को कम करने से प्रदर्शन में वृद्धि नहीं होगी? यह भी कम से कम आक्रामक परिवर्तन है। मैं सराहना करता हूं कि आपको मूल्यों से बचने की आवश्यकता होगी। हां, पूरा बैच एक प्रो निष्पादन के बजाए त्रुटि करेगा, जो किया जा रहा है, उसके अर्थशास्त्र के आधार पर, आप पूरी तरह से रोलबैक करना चाहते हैं, जो बैचिंग के साथ अभी भी संभव है। मैंने एसक्यूएलसीएलआर का उपयोग नहीं किया है, इसलिए इसके बारे में मैंने जो पढ़ा है उससे इस पर टिप्पणी नहीं कर सकती है, यह परिदृश्य इसके लिए उचित उपयोग हो सकता है। –

16

आप एसक्यूएल 2008 उपयोग कर रहे हैं, तो आप एक table-valued parameter एक s'proc कॉल में अद्यतन के सभी पुश करने के लिए उपयोग कर सकते हैं।

अद्यतन संयोग से, हम merge बयान के साथ संयोजन में इस का उपयोग कर रहे हैं। इस तरह एसक्यूएल सर्वर यह पता लगाने का ख्याल रखता है कि क्या हम नए रिकॉर्ड डालने या मौजूदा लोगों को अपडेट कर रहे हैं। यह तंत्र हमारे वेब ऐप के कई प्रमुख स्थानों पर उपयोग किया जाता है और एक समय में सैकड़ों परिवर्तनों को संभालता है। नियमित रूप से लोड के दौरान हम इस proc चारों ओर कहा जाता हो 50 बार एक दूसरे देखेंगे और वह और अधिक तेज़ी किसी अन्य तरीके से हमें पता चला है की तुलना में है ... और निश्चित रूप से एक बहुत बड़ा डीबी सर्वर खरीदने की तुलना में सस्ता।

+1

सहायक लिंक: http://msdn.microsoft.com/en-us/library/bb675163.aspx –

+0

मैंने उन लोगों के बारे में नहीं सुना था। सलाह के लिये धन्यवाद। क्या आप क्लाइंट और संग्रहीत प्रो परिभाषा दोनों में कोड में इसका उपयोग कैसे कर सकते हैं इसका एक उदाहरण दिखा सकते हैं या लिंक कर सकते हैं? –

+0

@ एडम आपने मुझे मार दिया! धन्यवाद! –

0

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

protected OleDbCommand oSQLInsert = new OleDbCommand(); 
// the "?" are place-holders for parameters... can be named parameters, 
// just for visual purposes 
oSQLInsert.CommandText = "insert into MyTable (fld1, fld2, fld3) values (?, ?, ?)"; 
// Now, add the parameters 
OleDbParameter NewParm = new OleDbParameter("parmFld1", 0); 
oSQLInsert.Parameters.Add(NewParm); 

NewParm = new OleDbParameter("parmFld2", "something"); 
oSQLInsert.Parameters.Add(NewParm); 

NewParm = new OleDbParameter("parmFld3", 0); 
oSQLInsert.Parameters.Add(NewParm); 

अब, एसक्यूएल आदेश, और जगह-धारकों सब जाने के लिए तैयार हैं ... तब, जब मैं कर रहा हूँ इसे कहते दरअसल करने के लिए तैयार है, मैं की तरह ..

oSQLInsert.Parameters[0].Value = 123; 
oSQLInsert.Parameters[1].Value = "New Value"; 
oSQLInsert.Parameters[2].Value = 3; 

फिर, बस इसे अमल कुछ करना होगा। कॉल की 100 की पुनरावृत्ति अधिक से अधिक

अच्छी किस्मत अपने आदेश बनाने ... द्वारा समय मार कर।

+0

मैं यह सुनिश्चित करने के लिए प्रोफाइल के माध्यम से इसे चलाऊंगा कि कन्स्ट्रक्टर और संग्रह वास्तव में समय खा रहे हैं। –

0

क्या यह एक बार की कार्रवाई है (जैसे "केवल उन 368 नए ग्राहकों को आयात करें") या क्या आपको नियमित रूप से 368 स्पोक कॉल करना पड़ता है?

यदि यह एक बार की कार्रवाई है, बस 368 कॉल के साथ चलते हैं।
(यदि स्पोक केवल अपडेट से कहीं अधिक है और प्रदर्शन को खींचने की संभावना है, तो इसे शाम या रात में चलाएं या जब भी कोई काम नहीं कर रहा हो)।

IMO, डेटाबेस के समय से पहले अनुकूलन एक बार कार्रवाई के लिए कॉल बार जब आप इसे साथ बिताने के लायक नहीं है।

0

बल्क CSV आयात

(1) स्ट्रिंग बिल्डर के माध्यम से डेटा उत्पादन का निर्माण के रूप में सीएसवी तो एक थोक CSV आयात करते हैं:

http://msdn.microsoft.com/en-us/library/ms188365.aspx

+2

मैन्युअल रूप से सीएसवी में अपना डेटा सहेज रहा है और फिर सीएसवी लोड करना बदसूरत है। इस उद्देश्य के लिए 'SqlBulkCopy' का उपयोग करें। – Brian

1

आप एसक्यूएल सर्वर से पहले के एक संस्करण का उपयोग कर रहे हैं, तो 2008 तक, आप अपने कोड को पूरी तरह से संग्रहित प्रक्रिया में ले जा सकते हैं।

वहाँ अच्छा कर रहे हैं और इस बारे में "बुरा" बातें।
अच्छा

  • एक नेटवर्क तार भर में डेटा खींचने के लिए कोई ज़रूरत नहीं।
  • तेज़ अपने तर्क
  • तराजू सेट किया गया है आधारित अप

बुरा

  • आप डेटाबेस में किसी भी तर्क के खिलाफ नियम है, तो यह आपके डिजाइन टूट जाएगा यदि।
  • तर्क आधारित तो आप अप प्रदर्शन की समस्याओं
  • आप बाहर निर्भरता है, तो का एक अलग सेट के साथ समाप्त हो सकता है सेट नहीं किया जा सकता है, तो यह कठिनाई बढ़ सकती है।

डेटा पर आप जो भी संचालन कर रहे हैं, उसके बारे में विवरण के बिना ठोस अनुशंसा करना मुश्किल है।

अद्यतन
बेन पूछा मैं CLR और SQL सर्वर के बारे में मेरी टिप्पणी से एक में क्या मतलब। Using CLR Integration in SQL Server 2005 पढ़ें। मूल विचार यह है कि आप अपने डेटा मैनिपुलेशन करने के लिए नेट कोड लिख सकते हैं और यह कोड SQL सर्वर के अंदर ही रहता है। यह आपको नेटवर्क पर सभी डेटा पढ़ने और उस तरह से अपडेट भेजने के लिए बचाता है।

कोड आपके मौजूदा प्रोसेस द्वारा कॉल करने योग्य है और आपको .NET की पूरी शक्ति देता है ताकि आपको कर्सर जैसी चीजें न करें। एसक्यूएल सेट आधारित रहेगा जबकि .NET कोड व्यक्तिगत रिकॉर्ड पर संचालन कर सकता है।

संयोग से, यह कैसे heirarchyid जैसी चीजों एसक्यूएल 2008

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

+0

@ क्रिस आप कोड को पूरी तरह से संग्रहीत प्रो में स्थानांतरित करने के बारे में एक अच्छा बिंदु लाते हैं। समस्या यह है कि "ऑटो-छूट" तर्क थोड़ा जटिल है और लगभग निश्चित रूप से संग्रहीत प्रो में कर्सर का उपयोग करने की आवश्यकता होगी। एक कोड परिप्रेक्ष्य से मुझे बनाए रखना मुश्किल लगता है। –

+0

@ बेन मैककॉर्मैक: उस स्थिति में आपके पास अभी भी SQL सर्वर के कुछ संस्करणों के तहत एक और विकल्प उपलब्ध है: सीएलआर। लेकिन अब हम जमीन पर चल रहे हैं कि ज्यादातर लोग अच्छे कारण से दूर रहते हैं। ;) – NotMe

+0

@Chris जब आप कहते हैं कि SQL सर्वर के साथ काम करते समय CLR एक विकल्प है तो आप क्या करते हैं? जाहिर है, सीएलआर * वह इंजन है जो .NET प्रबंधित कोड चलाता है, लेकिन SQL सर्वर के साथ क्या करना है? –

0

तालिका-मूल्यवान पैरामीटर सर्वश्रेष्ठ होंगे, लेकिन चूंकि आप SQL 05 पर हैं, तो आप रिकॉर्ड के बैच डालने के लिए SqlBulkCopy कक्षा का उपयोग कर सकते हैं। मेरे अनुभव में, यह बहुत तेज है।

संबंधित मुद्दे

 संबंधित मुद्दे