2009-07-14 13 views
5

हम SQL सर्वर 2005 का उपयोग करते हैं। हमारे सभी डेटा एक्सेस संग्रहीत प्रक्रियाओं के माध्यम से किया जाता है। हमारी चयन संग्रहित प्रक्रियाएं हमेशा कई परिणाम सेट लौटाती हैं।एसक्यूएल संग्रहीत प्रक्रियाओं में कोड का पुन: उपयोग कैसे करें?

उदाहरण के लिए:

CREATE PROCEDURE hd_invoice_select(@id INT) AS 
    SELECT * FROM Invoice WHERE InvoiceID = @id 
    SELECT * FROM InvoiceItem WHERE InvoiceID = @id 
    SELECT * FROM InvoiceComments WHERE InvoiceID = @id 
    RETURN 

हमारे आवेदन के डेटा का उपयोग स्तर एक ऑब्जेक्ट परिणाम (ओ/आर मैपर शैली) पर आधारित ग्राफ बनाता है।

मेरी समस्या यह है कि हमारे पास कई अलग-अलग चालान चयन संग्रहित प्रोसेस हैं। वे सभी अलग-अलग चयन मानदंडों के लिए, एक ही संरचना को वापस करते हैं। उदाहरण के लिए, मैं भी है:

CREATE PROCEDURE hd_invoice_selectAllForCustomer(@customerID INT) AS 
    SELECT * FROM Invoice WHERE CustomerID = @customerID 
    SELECT * FROM InvoiceItem WHERE InvoiceID IN 
     (SELECT InvoiceID FROM Invoice WHERE CustomerID = @customerID) 
    SELECT * FROM InvoiceComments WHERE InvoiceID = @id 
     (SELECT InvoiceID FROM Invoice WHERE CustomerID = @customerID) 
    RETURN 

और मैं सहित कई अन्य लोगों के होते हैं:

hd_invoice_selectActive() 
hd_invoice_selectOverdue() 
hd_invoice_selectForMonth(@year INT, @month INT) 

और मैं अवधारणाओं का एक बहुत के लिए एक ही पैटर्न (ग्राहकों, कर्मचारियों, आदि)

है हम बहुत सारे कोड की प्रतिलिपि बनाते हैं और रखरखाव वास्तव में कठिन है। जब एक अवधारणा की "संरचना" बदल जाती है, तो हमें सभी प्रोसेस को ठीक करना और ठीक करना पड़ता है और यह बहुत ही त्रुटि प्रवण होता है।

तो मेरा सवाल है: परिदृश्य में कोड का पुन: उपयोग करने का सबसे अच्छा तरीका क्या है?

हम एक समाधान के साथ आए जो temp तालिकाओं का उपयोग करता है। लेकिन यह बहुत ही सुरुचिपूर्ण नहीं है। मैं आपको अपने विचार साझा करने दूंगा और यदि आवश्यक हो तो मैं उस दृष्टिकोण पर आपकी टिप्पणियां प्राप्त करने के लिए आगामी समाधान में अपने समाधान का विवरण पोस्ट करूंगा।

धन्यवाद

उत्तर

1

इसे दूसरे उत्तर के रूप में पोस्ट करना क्योंकि यह एक अलग दृष्टिकोण है। यदि आप SQL Server 2008 का उपयोग कर रहे हैं:

CREATE TYPE InvoiceListTableType AS TABLE 
(
    InvoiceId INT 
); 
GO 

CREATE PROCEDURE hd_invoice_selectFromTempTable 
(
    @InvoiceList InvoiceListTableType READONLY 
) 
AS 
BEGIN 
    SELECT * FROM Invoice WHERE InvoiceID IN 
     (SELECT InvoiceId FROM @InvoiceList) 

    SELECT * FROM InvoiceItem WHERE InvoiceID IN 
     (SELECT InvoiceId FROM @InvoiceList) 

    SELECT * FROM InvoiceComments WHERE InvoiceID IN 
     (SELECT InvoiceId FROM @InvoiceList) 

    RETURN 
END 
GO 

CREATE PROCEDURE hd_invoice_select(@id INT) AS 
BEGIN 
    DECLARE @InvoiceList AS InvoiceListTableType; 

    SELECT id AS ID 
     INTO @InvoiceList 

    EXEC hd_invoice_selectFromTempTable(@InvoiceList) 
    RETURN 
END 
GO 

CREATE PROCEDURE hd_invoice_selectAllForCustomer(@customerID INT) AS 
BEGIN 
    DECLARE @InvoiceList AS InvoiceListTableType; 

    SELECT invoiceID as ID 
     INTO @InvoiceList 
     FROM Invoice WHERE CustomerID = @customerID 

    EXEC hd_invoice_selectFromTempTable(@InvoiceList) 
    RETURN 
END 
GO 

CREATE PROCEDURE hd_invoice_selectAllActive AS 
BEGIN 
    DECLARE @InvoiceList AS InvoiceListTableType; 

    SELECT invoiceID as ID 
     INTO @InvoiceList 
     FROM Invoice WHERE Status = 10002 

    EXEC hd_invoice_selectFromTempTable(@InvoiceList) 
    RETURN 
END 
GO 
+0

यह बहुत अच्छा है। क्या आपको कोई विचार है कि यह कैसे करता है? क्या क्वेरी ऑप्टिमाइज़र अच्छा काम कर रहा है? आंतरिक रूप से, क्या यह temp तालिकाओं का उपयोग कर रहा है या यह वास्तव में सेट को एक साधारण मान के रूप में पास कर रहा है। – Sylvain

+0

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

+0

जैसे ही हम SQL 2008 में जाते हैं, हम इस दृष्टिकोण का उपयोग करने के लिए प्रतिक्रिया देंगे। – Sylvain

0

इस संग्रहित प्रक्रियाओं और क्यों लोग उन्हें पसंद नहीं है के साथ मुख्य समस्याओं में से एक है।

मुझे कभी भी इसके आसपास कोई रास्ता नहीं मिला या देखा नहीं है।

0

मैंने अपने मूल सीआरयूडी के लिए कोड जेनरेटर द्वारा जेनरेट की गई संग्रहित प्रक्रियाओं का उपयोग करना शुरू कर दिया है। मैं रिपोर्ट या जटिल एसक्यूएल काम के लिए संग्रहीत प्रोसेस का उपयोग करता हूं।

मेरे पास आपके प्रश्न से संबंधित कोई सुझाव नहीं है - IN खंड का उपयोग करने के बजाय, अपने SQL कथन में EXISTS क्लॉज का उपयोग करें।

+1

क्या आप समझा सकते हैं कि ऐसा क्यों लगता है कि इस मामले में EXISTS बेहतर है? –

+1

EXISTS के बजाय IN का उपयोग उप-क्वेरी डेटा के तालिका स्कैन का कारण बन सकता है। EXISTS इंडेक्स का बेहतर उपयोग कर सकते हैं। इन क्वेरी को प्राथमिक क्वेरी के माध्यम से प्रत्येक पास पर उप-क्वेरी में आइटम्स की सूची को खोजने का भी कारण बन सकता है। –

2

इस विशिष्ट परिदृश्य के लिए "सर्वश्रेष्ठ" तरीका कुछ प्रकार की कोड जनरेशन का उपयोग करना होगा। कुछ प्रकार के सम्मेलन के साथ आओ और इसे कोड जनरेटर में प्लग करें।

0

मैं कभी कभी दो चरणों में कर:

मैं InvoiceID की एक सूची के साथ आने के। फिर मैं अपनी संग्रहित प्रक्रिया को इस सूची के साथ पैरामीटर के रूप में कॉल करता हूं।

2005 को हम तालिका महत्वपूर्ण पैरामीटर नहीं है, तो मैं एक बाइनरी ब्लॉब में आईडी की मेरी सूची में पैक और यहां बताए अनुसार, एसक्यूएल सर्वर में जमा करें: Arrays and Lists in SQL Server 2005

तुम भी आईडी की सूची प्रस्तुत कर सकते हैं एक अल्पविराम से अलग सूची (कुछ हद तक धीमी) या निश्चित चौड़ाई स्ट्रिंग प्रस्तुतियों (बहुत तेज़) के एक संयोजन के रूप में।

+0

इस तकनीक का उपयोग करके, आप इसे कैसे बना सकते हैं ताकि proc hd_invoice_selectForMonth (@year INT, @month INT) मिलान करने वाली आईडी पा सकें और फिर उन्हें पैक कर सकें और उन्हें hd_invoice_selectFromIDs (@ids blob) पर भेज सकें? – Sylvain

0

मुझे एक ऐसा एप्लिकेशन मिला है जिसने पहले temp तालिका दृष्टिकोण का उपयोग किया था और मैं मानता हूं कि यह बहुत गन्दा है।

उस प्रोजेक्ट पर हम उन अस्थायी 'ऑब्जेक्ट्स' वाले दृश्यों के साथ उन्हें बदलकर कई अस्थायी तालिकाओं को हटाने में सक्षम थे, फिर हमने उन दृश्यों से पूछने के लिए हमारी संग्रहीत प्रक्रियाओं को अपडेट किया।

शायद यह आपकी स्थिति में भी काम कर सकता है।

1

क्या आपने अपनी मुख्य प्रो के पैरामीटर की सूची में 1 से अधिक क्वेरी पैरामीटर प्रकार डालने का प्रयास किया है? मैंने केवल चालान तालिका को कवर करने के लिए proc लिखा था, आपको इसे अपनी अतिरिक्त तालिकाओं के लिए विस्तारित करने की आवश्यकता होगी।

CREATE PROCEDURE hd_invoice_select 
(
    @id INT = NULL 
    , @customerId INT = NULL 
) AS 
BEGIN 
    SELECT * 
     FROM Invoice 
     WHERE 
      (
       @id IS NULL 
       OR InvoiceID = @id 
      ) 
      AND (
       @customerId IS NULL 
       OR CustomerID = @customerId 
      ) 
    RETURN 
END 

इस proc एक विशिष्ट शून्य के रूप में @customerId साथ @id के आधार पर InvoiceID के लिए, NULLs रूप @id और @customerId भेजकर खुली कहा जा सकता है (या बस इसे बंद कर छोड़ सब एक साथ), या एक के लिए विशिष्ट ग्राहक @customerId पर आधारित @id को NULL के रूप में छोड़कर या क्वेरी से बाहर कर दें।

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

+2

क्रिस, यह मूल रूप से वही समाधान है जिसका हम उपयोग करते हैं, लेकिन एक मामूली परिवर्तन के साथ। WHERE खंड में हम उपयोग करेंगे: ग्राहक आईडी = ISNULL (@customerId, ग्राहक आईडी) कारण यह है कि यह मूल्य शून्य होने पर सभी वस्तुओं को वापस करने का दुष्प्रभाव देता है। इस तरह यदि हम पैरामीटर के बिना EXEC hd_invoice_select() को कॉल करते हैं, तो हम एक पूर्ण सूची प्राप्त कर सकते हैं। यह ऐसा कुछ नहीं हो सकता है जिसे आप चाहते हैं, लेकिन हमें यह बहुत उपयोगी लगता है। चीयर्स! -Erick – Erick

+0

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

+0

अंतिम टिप्पणी पर इसे शामिल करने का अर्थ: मैं निश्चित रूप से आपके दृष्टिकोण की संक्षिप्तता की सराहना करता हूं। –

0

कुछ मामलों में मैं "कोड" का पुन: उपयोग करने के लिए दृश्यों का उपयोग करता हूं। फिल्टर, सक्रिय आइटम, पुरानी चीजें, और इसी तरह के मामलों में ...

0

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

+0

@ एचएलजीईएम: आप जॉइन का उपयोग करके कई परिणाम कैसे वापस कर देंगे? मुझे चालान की आवश्यकता है, चालान के सभी आइटम और चालान के लिए सभी टिप्पणियां 3 परिणाम के रूप में लौटा दी गई हैं। – Sylvain

1

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

यह दृष्टिकोण काम करता है और उपयोग करने में आसान है। मुझे नहीं पता कि इसका प्रदर्शन प्रभाव पड़ता है क्योंकि यह अस्थायी तालिकाओं पर भारी निर्भर करता है।

अपने आवेदन में एक अवधारणा के लिए, मैं इस तरह एक storec proc है:

CREATE PROCEDURE hd_invoice_selectFromTempTable AS 

    /* Get the IDs from an existing #TempInvoiceIDs temporary table */ 

    SELECT * FROM Invoice WHERE InvoiceID IN 
     (SELECT ID FROM #TempInvoiceIDs) 

    SELECT * FROM InvoiceItem WHERE InvoiceID IN 
     (SELECT ID FROM #TempInvoiceIDs) 

    SELECT * FROM InvoiceComments WHERE InvoiceID IN 
     (SELECT ID FROM #TempInvoiceIDs) 

    RETURN 

तो मैं के रूप में कई चयन संग्रहीत proc बनाने के रूप में मैं की जरूरत है:

CREATE PROCEDURE hd_invoice_select(@id INT) AS 

    /* Fill #TempInvoiceIDs with matching IDs */ 
    SELECT id AS ID INTO #TempInvoiceIDs 

    EXEC hd_invoice_selectFromTempTable 
    RETURN 

CREATE PROCEDURE hd_invoice_selectAllForCustomer(@customerID INT) AS 

    /* Fill #TempInvoiceIDs with matching IDs */ 
    SELECT invoiceID as ID 
    INTO #TempInvoiceIDs 
    FROM Invoice WHERE CustomerID = @customerID 

    EXEC hd_invoice_selectFromTempTable 
    RETURN 

CREATE PROCEDURE hd_invoice_selectAllActive AS 

    /* Fill #TempInvoiceIDs with matching IDs */ 
    SELECT invoiceID as ID 
    INTO #TempInvoiceIDs 
    FROM Invoice WHERE Status = 10002 

    EXEC hd_invoice_selectFromTempTable 
    RETURN 

आप को क्या समझते हो यह दृष्टिकोण? यह कुछ हद तक AlexKuznetsov के उत्तर के समान है लेकिन मैं एक BLOB पैरामीटर के बजाय temp टेबल का उपयोग करता हूं।

+1

जब आप temp तालिकाओं का उपयोग करते हैं, तो वे (सीपीयू) बहुत सी CPU का उपयोग करते हुए हर समय पुन: संकलित करते हैं - कभी-कभी हमें इसकी आवश्यकता होती है, आमतौर पर हम नहीं करते हैं। आप अल्पविराम से अलग सूची (कुछ हद तक धीमी) के रूप में या निश्चित चौड़ाई स्ट्रिंग प्रस्तुतियों (बहुत तेज़) के एक संयोजन के रूप में आईडी की एक सूची भी सबमिट कर सकते हैं - जिसके लिए रीकंपाइल की आवश्यकता नहीं होती है। –

+0

बहुत उपयोगी टिप्पणी, धन्यवाद। क्या कुल निष्पादन समय के विरुद्ध महत्वपूर्ण प्रक्रिया को पुन: संकलित करने का समय है? यदि एक प्रो को पुन: संकलित करने के लिए 2ms और 120ms निष्पादित करने के लिए लेता है, तो पुनर्मूल्यांकन समय वास्तव में महत्वपूर्ण नहीं है। सही? – Sylvain

+0

मुझे यह दृष्टिकोण पसंद है, क्योंकि यह SQL सर्वर के लिए स्वाभाविक वस्तुओं का उपयोग कर सीधे आगे है। –

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