2009-06-17 16 views
5

में मूल्यांकन चलो कहते हैं कि मैं एक पर एक समारोह फोन है का चयन करते हैं या जहां इस तरह Oracle में खंड:ओरेकल और SQLServer समारोह प्रश्नों

select a, b, c, dbms_crypto.hash(utl_raw.cast_to_raw('HELLO'),3) 
    from my_table 

ऐसा ही एक उदाहरण एमएस SQLServer के लिए निर्माण किया जा सकता।

प्रत्येक मामले में अपेक्षित व्यवहार क्या है?

HASH समारोह, तालिका में प्रत्येक पंक्ति के लिए एक बार के नाम से जाना जा रहा है, या डीबीएमएस बहुत चालाक समारोह सिर्फ एक बार फोन करने के लिए किया जाएगा के बाद से यह लगातार मानकों के साथ एक समारोह और कोई दुष्प्रभाव है है?

बहुत बहुत धन्यवाद।

+0

डीबी लोगों के लिए अच्छा सवाल। +1 – shahkalpesh

उत्तर

8

ओरेकल का उत्तर यह निर्भर करता है। समारोह को चयनित प्रत्येक पंक्ति के लिए बुलाया जाएगा, फंक्शन को 'निर्धारण' चिह्नित किया गया है, इस मामले में इसे केवल एक बार बुलाया जाएगा।

CREATE OR REPLACE PACKAGE TestCallCount AS 
    FUNCTION StringLen(SrcStr VARCHAR) RETURN INTEGER; 
    FUNCTION StringLen2(SrcStr VARCHAR) RETURN INTEGER DETERMINISTIC; 
    FUNCTION GetCallCount RETURN INTEGER; 
    FUNCTION GetCallCount2 RETURN INTEGER; 
END TestCallCount; 

CREATE OR REPLACE PACKAGE BODY TestCallCount AS 
    TotalFunctionCalls INTEGER := 0; 
    TotalFunctionCalls2 INTEGER := 0; 

    FUNCTION StringLen(SrcStr VARCHAR) RETURN INTEGER AS 
    BEGIN 
     TotalFunctionCalls := TotalFunctionCalls + 1; 
     RETURN Length(SrcStr); 
    END; 
    FUNCTION GetCallCount RETURN INTEGER AS 
    BEGIN 
     RETURN TotalFunctionCalls; 
    END; 

    FUNCTION StringLen2(SrcStr VARCHAR) RETURN INTEGER DETERMINISTIC AS 
    BEGIN 
     TotalFunctionCalls2 := TotalFunctionCalls2 + 1; 
     RETURN Length(SrcStr); 
    END; 
    FUNCTION GetCallCount2 RETURN INTEGER AS 
    BEGIN 
     RETURN TotalFunctionCalls2; 
    END; 

END TestCallCount; 




SELECT a,TestCallCount.StringLen('foo') FROM(
    SELECT 0 as a FROM dual 
    UNION 
    SELECT 1 as a FROM dual 
    UNION 
    SELECT 2 as a FROM dual 
); 

SELECT TestCallCount.GetCallCount() AS TotalFunctionCalls FROM dual; 

आउटपुट:

A      TESTCALLCOUNT.STRINGLEN('FOO') 
---------------------- ------------------------------ 
0      3        
1      3        
2      3        

3 rows selected 


TOTALFUNCTIONCALLS  
---------------------- 
3      

1 rows selected 

तो StringLen() फ़ंक्शन पहले मामले में तीन बार बुलाया गया था। अब जब StringLen2() जो नियतात्मक निरूपित किया जाता है के साथ क्रियान्वित:

SELECT a,TestCallCount.StringLen2('foo') from(
    select 0 as a from dual 
    union 
    select 1 as a from dual 
    union 
    select 2 as a from dual 
); 

SELECT TestCallCount.GetCallCount2() AS TotalFunctionCalls FROM dual; 

परिणाम:

A      TESTCALLCOUNT.STRINGLEN2('FOO') 
---------------------- ------------------------------- 
0      3        
1      3        
2      3        

3 rows selected 

TOTALFUNCTIONCALLS  
---------------------- 
1      

1 rows selected 

तो StringLen2() फ़ंक्शन केवल एक बार बुलाया गया था के बाद से यह नियतात्मक चिह्नित किया गया था।

एक समारोह के लिए नियतात्मक चिह्नित नहीं, तो आप इस तरह के रूप आपकी क्वेरी को संशोधित करके इस के आसपास मिल सकती है:

select a, b, c, hashed 
    from my_table 
cross join (
    select dbms_crypto.hash(utl_raw.cast_to_raw('HELLO'),3) as hashed from dual 
); 
+0

उदाहरण के लिए धन्यवाद, मार्क। स्ट्रिंगलेन फ़ंक्शन को कॉल करते समय आपके उदाहरण में एक साइड-इफेक्ट है (कुल कार्यक्षमता कॉल: = कुल फ़ंक्शन कॉल + 1;)। तो मुझे नहीं लगता कि ओरेकल इस मामले में अनुकूलित करने में सक्षम होगा। –

+0

बहुत बढ़िया मार्क। महान उदाहरण। आप इसे चलाने के लिए क्या ओरेकल संस्करण का उपयोग करते थे? –

+0

@ पाब्लो जहां तक ​​मुझे पता है कि आप किसी भी कार्य को निर्धारिती के रूप में चिह्नित कर सकते हैं और यह सुनिश्चित करना आपकी ज़िम्मेदारी है कि कोई दुष्प्रभाव नहीं हैं। यदि dbms_crypto.hash() निश्चित नहीं है तो आप हमेशा अपना स्वयं का फ़ंक्शन निर्धारित निर्धारिती घोषित कर सकते हैं और इसके बजाए कॉल कर सकते हैं। मैंने इसे ओरेकल एक्सई पर चलाया (जो कि 10 जी पर आधारित है)। –

4

SQL सर्वर के लिए, इसका मूल्यांकन प्रत्येक पंक्ति के लिए किया जाएगा।

आप एक बार फ़ंक्शन को चलाकर और एक चर को असाइन करके और क्वेरी में चर का उपयोग करके बहुत बेहतर हो जाएंगे।

+1

आपने मुझे हराया, मेरे पास समान अंक थे लेकिन आपने तेज़ी से टाइप किया था। – HLGEM

1

संक्षिप्त उत्तर .... यह निर्भर करता है।

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

कुछ आप में देखना चाहते हो सकता है सबक्वेरी के साथ Oracle है:

साथ query_name खंड आप एक सबक्वेरी ब्लॉक को नाम निर्दिष्ट करने देता है। आप फिर क्वेरी नाम निर्दिष्ट करते हुए द्वारा क्वेरी में एकाधिक स्थानों पर subquery ब्लॉक संदर्भित कर सकते हैं।ओरेकल या तो एक इनलाइन दृश्य या अस्थायी तालिका

मैं here से उद्धृत पाठ मिल गया है, जो उदाहरण के बहुत सारे के रूप में के रूप में क्वेरी नाम का इलाज क्वेरी अनुकूलित करता है।

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