2012-01-22 12 views
5

निम्नलिखित टी-एसक्यूएल कथन में, dbo.FUNC फ़ंक्शन को कितनी बार कॉल किया जाएगा?जब एक ही यूडीएफ में एकाधिक कॉल एक ही कथन में होते हैं, तो इसे कितनी बार बुलाया जाएगा?

SELECT 
    column1, 
    column2, 
    dbo.FUNC(column3) AS column3 
FROM table1 
WHERE dbo.FUNC(column3) >= 5 
ORDER BY dbo.FUNC(column3) DESC 

यह पंक्ति प्रति अधिक अलग-अलग बार बुलाया जाएगा, या अनुकूलक पहचान करता है कि यह एक एकल बयान में कई बार इस्तेमाल किया जा रहा है, और केवल एक बार कहते हैं?

मैं इसका परीक्षण कैसे कर सकता हूं? मैं किसी फ़ंक्शन के अंदर एक टेबल में सम्मिलित नहीं कर सकता, इसलिए एक काउंटर काम नहीं कर रहा है ...

उत्तर

11

यह गारंटी नहीं है।

आपको पता लगाने के लिए निष्पादन योजना की जांच करनी होगी। कुछ उदाहरण।

CREATE FUNCTION dbo.FUNC1(@p1 int) 
RETURNS int 
AS 
BEGIN 
    RETURN @p1 + 1 
END 

GO 

CREATE FUNCTION dbo.FUNC2(@p1 int) 
RETURNS int 
WITH SCHEMABINDING 
AS 
BEGIN 
    RETURN @p1 + 1 
END 

GO 
SELECT 
     OBJECTPROPERTYEX(OBJECT_ID('dbo.FUNC1'), 'IsDeterministic'), 
     OBJECTPROPERTYEX(OBJECT_ID('dbo.FUNC2'), 'IsDeterministic') 
GO 

FUNC2WITH SCHEMABINDING बनाई गई है और नियतात्मक माना जाता है। FUNC1 नहीं है।

SELECT 
    dbo.FUNC1(number) AS FUNC1, 
    dbo.FUNC2(number) AS FUNC2 
FROM master..spt_values 
WHERE dbo.FUNC1(number) >= 5 AND dbo.FUNC2(number) >= 5 
ORDER BY dbo.FUNC1(number), dbo.FUNC2(number) 

, योजना

PLAN1

|--Sort(ORDER BY:([Expr1003] ASC, [Expr1004] ASC)) 
     |--Compute Scalar(DEFINE:([Expr1003]=[test].[dbo].[FUNC1]([master].[dbo].[spt_values].[number]))) 
      |--Filter(WHERE:([test].[dbo].[FUNC1]([master].[dbo].[spt_values].[number])>=(5) AND [Expr1004]>=(5))) 
       |--Compute Scalar(DEFINE:([Expr1004]=[test].[dbo].[FUNC2]([master].[dbo].[spt_values].[number]))) 
         |--Index Scan(OBJECT:([master].[dbo].[spt_values].[ix2_spt_values_nu_nc])) 

FUNC1 दो बार (एक बार फिल्टर में और एक बार एक गणना अदिश में दोनों प्रक्षेपण और आदेश देने के लिए प्रयोग किया जाता है एक गणना स्तंभ outputting) मूल्यांकन किया जाता है देता है FUNC2 केवल एक बार मूल्यांकन किया जाता है।

नए सिरे से लिखना के रूप में

SELECT 
    FUNC1, 
    FUNC2 
FROM master..spt_values 
CROSS APPLY (SELECT dbo.FUNC1(number), dbo.FUNC2(number)) C(FUNC1, FUNC2) 
WHERE FUNC1 >= 5 AND FUNC2 >= 5 
ORDER BY FUNC1, FUNC2 

योजना थोड़ा परिवर्तन और दोनों केवल एक बार

Plan 2

|--Sort(ORDER BY:([Expr1003] ASC, [Expr1004] ASC)) 
     |--Filter(WHERE:([Expr1003]>=(5))) 
      |--Compute Scalar(DEFINE:([Expr1003]=[test].[dbo].[FUNC1]([master].[dbo].[spt_values].[number]))) 
       |--Filter(WHERE:([Expr1004]>=(5))) 
         |--Compute Scalar(DEFINE:([Expr1004]=[test].[dbo].[FUNC2]([master].[dbo].[spt_values].[number]))) 
          |--Index Scan(OBJECT:([master].[dbo].[spt_values].[ix2_spt_values_nu_nc])) 

मूल्यांकन किया जाता है अब क्वेरी

SELECT 
    FUNC1 + 10, 
    FUNC2 + 10 
FROM master..spt_values 
CROSS APPLY (SELECT dbo.FUNC1(number), dbo.FUNC2(number)) C(FUNC1, FUNC2) 
WHERE FUNC1 >= 5 AND FUNC2 >= 5 
ORDER BY FUNC1, FUNC2 
को थोड़ा-बहुत बदलाव कर रही है

मूल परिणाम के विपरीत देता है कि FUNC2 का मूल्यांकन दो बार किया जाता है लेकिन FUNC1 केवल एक बार होता है।

Plan 3

|--Compute Scalar(DEFINE:([Expr1005]=[Expr1003]+(10))) 
     |--Sort(ORDER BY:([Expr1003] ASC, [Expr1004] ASC)) 
      |--Filter(WHERE:([Expr1003]>=(5))) 
       |--Compute Scalar(DEFINE:([Expr1003]=[test].[dbo].[FUNC1]([master].[dbo].[spt_values].[number]))) 
         |--Filter(WHERE:([Expr1004]>=(5))) 
          |--Compute Scalar(DEFINE:([Expr1004]=[test].[dbo].[FUNC2]([master].[dbo].[spt_values].[number]), [Expr1006]=[test].[dbo].[FUNC2]([master].[dbo].[spt_values].[number])+(10))) 
           |--Index Scan(OBJECT:([master].[dbo].[spt_values].[ix2_spt_values_nu_nc])) 
+1

से मान लेगा आप कैसे जानते हैं कि इसे दो बार बुलाया गया है? –

+1

योजना दिखाती है कि इसे फ़िल्टर अभिव्यक्ति में एक बार कहा जाता है, फिर अगला ऑपरेटर एक गणना स्केलर है जो फ़ंक्शन को दोबारा कॉल करता है, परिणाम को 'एक्सप्र 1003' कॉलम के रूप में आउटपुट करता है और उस कॉलम का चयन चयन और क्रम दोनों के लिए किया जाता है । –

+1

+ अच्छा उदाहरण। मुझे लगता है कि गैर-इन-लाइन-टेबल यूडीएफ * प्रति * प्रति पंक्ति प्रति बार एक बार मूल्यांकन किया जाता है जब तक कोई स्पष्ट शॉर्टकट नहीं होता है (उदाहरण के लिए ऑर्डर द्वारा ऑर्डर अभिव्यक्ति से सटीक मिलान करता है) – gbn

-2

हाँ।

ऑप्टिमाइज़र के पास चलते समय एक ही कैल्क में अनुकूलित करने के लिए पर्याप्त ज्ञान है।

आप इसे देखने के लिए निष्पादन योजना देख सकते हैं।

+0

हालांकि सीएलआर फ़ंक्शन, रिकर्सन और लूप की बात आती है तो निष्पादन योजना सटीक प्रतीत नहीं होती है। –

+0

क्या FUNC clr सक्षम func है? –

+0

मेरे मामले में, एफयूएनसी एक सीएलआर यूडीएफ –

1

सबसे पहले, उस पर निर्भर करता है, तो समारोह नियतात्मक है।

तब भी, इसका उपयोग केवल एक ही पंक्ति पर एकाधिक कॉल के लिए किया जाएगा।

मेरा मानना ​​है कि यदि कार्य निर्धारित है तो आपका केस अनुकूलित किया जाएगा।

+0

मेरा फ़ंक्शन निर्धारक है, हालांकि मैं उम्मीद कर रहा था एक "मैं निश्चित रूप से जानता हूं" उत्तर, और "मुझे विश्वास है" जवाब नहीं। –

+0

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

+0

+1 यदि मैं 'SCHEMABINDING के साथ' फ़ंक्शन बनाता हूं तो यह उत्तर का समर्थन करता है, फिर मेरे उत्तर में पहली क्वेरी में फ़िल्टर से पहले गणना स्केलर को स्थानांतरित करता है। –

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