यह गारंटी नहीं है।
आपको पता लगाने के लिए निष्पादन योजना की जांच करनी होगी। कुछ उदाहरण।
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
FUNC2
WITH 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)
, योजना
|--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
योजना थोड़ा परिवर्तन और दोनों केवल एक बार
|--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
केवल एक बार होता है।
|--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]))
से मान लेगा आप कैसे जानते हैं कि इसे दो बार बुलाया गया है? –
योजना दिखाती है कि इसे फ़िल्टर अभिव्यक्ति में एक बार कहा जाता है, फिर अगला ऑपरेटर एक गणना स्केलर है जो फ़ंक्शन को दोबारा कॉल करता है, परिणाम को 'एक्सप्र 1003' कॉलम के रूप में आउटपुट करता है और उस कॉलम का चयन चयन और क्रम दोनों के लिए किया जाता है । –
+ अच्छा उदाहरण। मुझे लगता है कि गैर-इन-लाइन-टेबल यूडीएफ * प्रति * प्रति पंक्ति प्रति बार एक बार मूल्यांकन किया जाता है जब तक कोई स्पष्ट शॉर्टकट नहीं होता है (उदाहरण के लिए ऑर्डर द्वारा ऑर्डर अभिव्यक्ति से सटीक मिलान करता है) – gbn