2009-05-13 14 views
7

अरे, मेरे पास SQL ​​Server 2000 (अभी अपडेट करने के लिए संभव नहीं है) के तहत संग्रहीत प्रक्रिया में एक कर्सर है जो सभी तालिका अपडेट करता है लेकिन इसे पूरा होने में आमतौर पर कुछ मिनट लगते हैं। मुझे इसे तेज बनाने की जरूरत है। यहां एक मनमानी उत्पाद आईडी द्वारा फ़िल्टर की गई उदाहरण तालिका है; Example table http://img231.imageshack.us/img231/9464/75187992.jpg जबकि जीडीईपीओ: प्रवेश डिपो, सीडीईपीओ: बाहर निकलें डिपो, एडेट: मात्रा, ई_CIKAN मात्रा जिसका उपयोग किया जाता है।टी-एसक्यूएल कर्सर को तेज़ी से कैसे बनाया जाए?

रिकार्ड explainations:
1: 10 इकाई छोड़ देता है 01 3: 5 यूनिट छोड़ देता है 01 (अब 1 रिकार्ड के लिए E_CIKAN 15 हो जाएगा) 4: 10 और इकाई में प्रवेश करती है डिपो 20 यूनिट डिपो 01, 2 में प्रवेश करती है 01. 5: 3 यूनिट 1 रिकॉर्ड से 01 छोड़ देता है। अब ध्यान दें कि 1 रिकॉर्ड में E_CIKAN 18 पर सेट है। 6: यह वह जगह है जहां समस्या आती है: 3 यूनिट को डिपो 01 छोड़ने की आवश्यकता होती है। इसमें 1 रिकॉर्ड से 2 यूनिट और 5 यूनिट से 1 इकाई होती है। मेरा एसपी तस्वीर में देखा गया यह जुर्माना संभाल सकता है, सिवाय इसके कि यह वास्तव में धीमा है।

यहां संग्रहित प्रक्रिया अंग्रेजी में अनुवादित है;

CREATE PROC [dbo].[UpdateProductDetails] 
as 
UPDATE PRODUCTDETAILS SET E_CIKAN=0; 
DECLARE @ID int 
DECLARE @SK varchar(50),@DP varchar(50) --SK = STOKKODU = PRODUCTID, DP = DEPOT 
DECLARE @DEMAND float  --Demand=Quantity, We'll decrease it record by record 
DECLARE @SUBID int 
DECLARE @SUBQTY float,@SUBCK float,@REMAINS float 
DECLARE SH CURSOR FAST_FORWARD FOR 
SELECT [ID],PRODUCTID,QTY,EXITDEPOT FROM PRODUCTDETAILS WHERE (EXITDEPOT IS NOT NULL) ORDER BY [DATE] ASC 
OPEN SH 
FETCH NEXT FROM SH INTO @ID, @SK,@DEMAND,@DP 

WHILE (@@FETCH_STATUS = 0) 
BEGIN 
    DECLARE SA CURSOR FAST_FORWARD FOR 
    SELECT [ID],QTY,E_CIKAN FROM PRODUCTDETAILS WHERE (QTY>E_CIKAN) AND ([email protected]) AND ([email protected]) ORDER BY [DATE] ASC 
    OPEN SA 
    FETCH NEXT FROM SA INTO @SUBID, @SUBQTY,@SUBCK 
    WHILE (@@FETCH_STATUS = 0) AND (@DEMAND>0) 
    BEGIN 
     SET @[email protected]@SUBCK 
     IF @DEMAND>@REMAINS --current record isnt sufficient, use it and move on 
     BEGIN 
     UPDATE PRODUCTDETAILS SET E_CIKAN=QTY WHERE [email protected]; 
     SET @[email protected]@REMAINS 
     END 
     ELSE 
     BEGIN 
     UPDATE PRODUCTDETAILS SET [email protected] WHERE [email protected]; 
     SET @DEMAND=0 
     END 
     FETCH NEXT FROM SA INTO @SUBID, @SUBAD,@SUBCK 
    END 
    CLOSE SA 
    DEALLOCATE SA 
    FETCH NEXT FROM SH INTO @ID, @SK,@DEMAND,@DP 
END 
CLOSE SH 
DEALLOCATE SH 
+0

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

+0

टॉम, मैंने अंग्रेजी में क्वेरी का अनुवाद किया है और कहा है कि 'जहां जीडीईपीओ: प्रवेश डिपो, सीडीईपीओ: बाहर निकलें डिपो, एडेट: मात्रा, ई_CIKAN मात्रा जिसका उपयोग किया जाता है।' इसके लिए स्क्रीनशॉट के बाद। –

+0

E_CIKAN मात्रा से दिखाए गए राशि (रिकॉर्ड का पालन करके) दिखाता है। पहले 3 रिकॉर्ड, 20 प्रविष्टि, 10 + 5 प्रस्थान की जांच करें। पहले रिकॉर्ड के लिए E_CIKAN 15 होगा। संग्रहीत प्रक्रिया यह ठीक है, समस्या यह वास्तव में धीमी है। –

उत्तर

10

इस सवाल का मेरे अन्य जवाब में हमारी बातचीत के आधार पर, मुझे लगता है कि मैं अपनी दिनचर्या में तेजी लाने के लिए एक रास्ता मिल गया है।

आप दो नेस्टेड कर्सर है:

  • पहले एक प्रत्येक पंक्ति किसी exitdepot निर्दिष्ट है कि का चयन किया गया है।
  • भीतरी कर्सर पाश उस उत्पाद/डिपो है कि निर्दिष्ट entrydepot के लिए पंक्तियों के माध्यम से चलाता है: यह उत्पाद, डिपो और राशि है, और फिर लेता है। यह प्रत्येक उत्पाद के लिए E_CIKAN पर जोड़ता है, जब तक कि यह सभी उत्पाद आवंटित नहीं करता है।

तो आंतरिक कर्सर लूप आपके पास प्रत्येक बाहर निकलने वाली पंक्ति के लिए कम-से-कम एक बार चलता है। हालांकि, आपकी प्रणाली वास्तव में परवाह नहीं करती है कि कौन से आइटम लेनदेन के साथ बाहर गए - आप केवल अंतिम E_CIKAN मानों की गणना करने की कोशिश कर रहे हैं।

तो ...

आपका बाहरी पाश केवल प्रत्येक उत्पाद/डिपो कॉम्बो के लिए बाहर भेज दिया मदों की कुल राशि प्राप्त करने की जरूरत है।इसलिए आप के लिए बाहरी कर्सर परिभाषा को बदल सकता है:

DECLARE SH CURSOR FAST_FORWARD FOR 
    SELECT PRODUCTID,EXITDEPOT, Sum(Qty) as TOTALQTY 
    FROM PRODUCTDETAILS 
    WHERE (EXITDEPOT IS NOT NULL) 
    GROUP BY PRODUCTID, EXITDEPOT 
OPEN SH 
FETCH NEXT FROM SH INTO @SK,@DP,@DEMAND 

(और उसके बाद भी बदल मिलान कोड से मिलान करने के अंत में एसएच से ला नहीं, जाहिर है)

इसका मतलब यह है अपने बाहरी कर्सर कई होगा कम पंक्तियों के माध्यम से लूप, और आपके भीतरी कर्सर रोचक रूप से पंक्तियों के समान पंक्तियों के बारे में सोचेंगे।

तो यह तेज़ होना चाहिए।

+0

से नीचे मेरा वैकल्पिक उत्तर देखें बहुत अच्छा लगता है। अभी यह तेजी से दोगुनी से अधिक है। मैं कल भी इसका परीक्षण करना जारी रखूंगा - यह देखने के लिए कि वास्तव में यह सही है कि, 'सही उत्तर' के रूप में चुनने से पहले। –

+0

तेजी से दोगुनी से अधिक! ठंडा। – codeulike

+4

अन्य पाठकों के लिए: यह 'चलने वाली कुल' क्वेरी समस्या का एक रूप है, और इसलिए वास्तव में उन दुर्लभ परिस्थितियों में से एक हो सकता है जहां कर्सर सबसे तेज़ (विश्वसनीय) समाधान प्रदान करते हैं। SqlServer चल रहे कुल योग पर सामान्य विवरण के लिए यह अन्य प्रश्न देखें: http://stackoverflow.com/questions/860966/calculate-a-running-total-in-sqlserver – codeulike

1

कर्सर को हटा दें और फिर से लिखने कि कर्सर की क्वेरी में शामिल होने से एक अपडेट के रूप में, आप आईएफएस एक मामला है, तो आप की जरूरत कर सकते हैं। मैं आज आपके लिए अद्यतन लिखने में बहुत व्यस्त हूं ...

1

कर्सर को हटाएं और बैच अपडेट करें। मुझे अभी तक एक अद्यतन नहीं मिला है जो बैच में नहीं किया जा सकता है।

2

टी-एसक्यूएल का उपयोग करते समय कर्सर को किसी भी समस्या का सबसे खराब प्रदर्शन समाधान होना चाहिए।

आप क्या तुम सच में पूरा करने के लिए कोशिश कर रहे हैं की जटिलता के आधार दो विकल्प हैं: सेट संचालन उपयोग करने के लिए कोड के पूरे सेट के पुनर्लेखन के लिए

  1. प्रयास। यह सबसे तेज़ प्रदर्शन करने वाला तरीका होगा ... लेकिन कभी-कभी आप इसे सेट ऑपरेशंस का उपयोग करके नहीं कर सकते हैं।

  2. कर्सर को तालिका चर (पहचान कॉलम के साथ), काउंटर, और लूप के संयोजन के साथ बदलें। फिर आप टेबल वैरिएबल की प्रत्येक पंक्ति के माध्यम से लूप कर सकते हैं। एक कर्सर से बेहतर प्रदर्शन करता है ... भले ही ऐसा प्रतीत नहीं होता है।

+0

मुझे पता नहीं है कि स्क्रीनशॉट में 6 वें रिकॉर्ड के क्लॉज के कारण UPDATE (यहां तक ​​कि अपडेट के साथ) द्वारा इसे कैसे किया जाए। ऐसा लगता है कि मुझे इसे दूसरे तरीके से करना होगा। –

+0

फिर, हम टेबल पंक्तियों के माध्यम से कैसे आगे बढ़ सकते हैं? – odiseh

1

सबसे पहले, यदि आप एक कर्सर का उपयोग करना चाहिए, और आप सामान अपडेट कर रहे हैं तो के लिए अपडेट खंड के साथ कर्सर घोषणा करते हैं। (नीचे उदाहरण देखें। ध्यान दें कि उदाहरण आपके कोड पर आधारित नहीं है।)

ऐसा कहकर, कर्सर के अलावा किसी अन्य चीज़ का उपयोग करने के कई तरीके हैं, अक्सर अस्थायी तालिकाओं का लाभ उठाते हैं। मैं कर्सर के बदले उस मार्ग की जांच करूंगा।

DECLARE LoopingCursor CURSOR LOCAL DYNAMIC 
FOR 
    select sortorder from customfielddefinition 
    where [email protected] 
FOR UPDATE OF sortorder 
+0

मैं इसे आजमा रहा हूं लेकिन किसी भी तरह से यह निम्नलिखित त्रुटि उठाता है, इसलिए मेरे पास चयनित भाग में पहचान कॉलम है .. 'अद्यतन के लिए केवल पढ़ने वाले कर्सर पर निर्दिष्ट नहीं किया जा सकता है।' –

+0

मैंने भी तेजी से आगे हटा दिया है, अभी भी कोई भाग्य नहीं है। मुझे लगता है कि यह SQL2000 की वजह से है .. लेकिन सवाल यह है कि, क्योंकि मैं पहले से ही कर्सर से @ID का उपयोग कर रहा हूं, क्या मैं वास्तव में अंतर कर सकता हूं यदि मैं एसएच का कहां उपयोग करता हूं? –

1

मैं देख सकता हूँ कि समस्या को हल करने की कोशिश कर रहे काफी जटिल है:

  • जब निर्दिष्ट GDEPO के साथ एक पंक्ति है, यह प्रतिनिधित्व करता शेयर डिपो में जा रहा है, और आप करना चाहते हैं की E_CIKAN का उपयोग करें जो कि पंक्ति को ट्रैक करने के लिए बाद में कितना स्टॉक उपयोग किया जाता है। E_CIKAN 0 से शुरू होगा और फिर एडीईटी तक पहुंचने तक स्टॉक के बाहर जाने के बाद जोड़ा जाएगा।

  • तो जब सीडीईपीओ निर्दिष्ट के साथ बाद की पंक्ति होती है, तो यह स्टॉक को बाहर जाने का वादा करता है, और आप जीडीईपीओ-पंक्ति के ई_CIKAN पर वापस जाना चाहते हैं और E_CIKAN को समायोजित करना चाहते हैं, इसमें स्टॉक-आउट की मात्रा जोड़कर ।

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

यह काफी मुश्किल गणना है।

कर्सर के बिना ऐसा करने का एक तरीका हो, जैसा कि अन्य सुझाव दे रहे हैं। लेकिन मुझे लगता है कि अगर आप अपनी टेबल को फिर से व्यवस्थित कर सकते हैं और डेटा को एक अलग तरीके से स्टोर कर सकते हैं, तो आप समस्या को आसान बना सकते हैं।

उदाहरण के लिए, बजाय एक ही मेज कि शेयर लेनदेन रिकॉर्ड में शेयर का ट्रैक रखने की है, तो आप 'product_id, Depo_id, राशि' कॉलम के साथ एक अलग तालिका कि प्रत्येक में प्रत्येक उत्पाद की कुल राशि का ट्रैक रखता हो सकता था एक समय में डेपो? ऐसी है कि के रूप में

एक डेटाबेस डिजाइन परिवर्तन चीजों को आसान बना सकता है।

या ... के बजाय क्या का ट्रैक रखने के E_CIKAN का उपयोग कर प्रयोग किया जाता है, इसका इस्तेमाल का ट्रैक क्या बनी हुई है रखने के लिए। और प्रत्येक पंक्ति में एक E_CIKAN मान रखें। तो जब भी स्टॉक में या एक डिपो से बाहर चला जाता है, E_CIKAN समय में उस बिंदु पर फिर से गणना और (बजाय पंक्ति 'में शेयर' वापस मूल जाता हूं और वहां इसे अद्यतन करने की कोशिश कर के) कि लेनदेन पंक्ति में संग्रहीत। फिर वर्तमान स्टॉक को खोजने के लिए, आप उस उत्पाद/डेपो के लिए सबसे हालिया ट्रांसकेशन देखें।

सारांश में, मैं यह है क्या कह रहा हूँ, अपने गणना धीमी और बोझिल है क्योंकि आप एक अजीब तरीके से डेटा भंडारण कर रहे हैं। लंबे समय तक प्रोग्रामिंग को आसान बनाने के लिए आपके डेटाबेस डिज़ाइन को बदलने के लायक हो सकते हैं।

+0

बिल्कुल, आपने मुझसे बेहतर समस्या का वर्णन किया है;)। अब मुद्दा यह है कि, संग्रहीत प्रक्रिया का उपयोग तब किया जाता है जब अतीत में रिकॉर्ड के लिए एक अद्यतन किया जाता है - अन्यथा मैं इसका उपयोग भी नहीं करता क्योंकि मैं नए रिकॉर्ड पर E_CIKAN की पुन: गणना करता हूं। मैं आपको डेटाबेस डिज़ाइन अनुशंसाओं के लिए धन्यवाद देना चाहता हूं लेकिन यह ऐसा कुछ है जिसे मैं अभी बर्दाश्त नहीं कर सकता। –

+0

ठीक है, तो आम तौर पर आप प्रत्येक लेनदेन के रूप में E_CIKAN की गणना करते हैं, लेकिन आपकी संग्रहीत प्रक्रिया कभी-कभी उपयोग की जाती है जब आपको वापस जाना और पिछले स्टॉक लेनदेन में संशोधन करना होता है? अब जब मैं एल्गोरिदम समझता हूं, तो मैं कुछ के साथ आने में सक्षम हो सकता हूं ... लेकिन सबसे पहले, चाय का एक बड़ा कप जरूरी है .... – codeulike

+0

ठीक है, मेरे पास एक कप चाय है और एक सुझाव के साथ आया है - – codeulike

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