SQL सर्वर 2012 और 2016 मानक: यदि मैं एक पैरामीटर के मान के आधार पर कोड की दो शाखाओं में से एक को निष्पादित करने के लिए संग्रहीत प्रक्रिया में if-else तर्क रखता हूं, तो इंजन नवीनतम संस्करण को कैश करता है?
नहीं, यह सभी संस्करणों को कैश करता है। या यों कहें, यह खोजे गए सभी रास्तों के साथ एक संस्करण को कैश करता है , जिसे चर में पारित किया जाता है।
स्टैक ओवरफ्लो डेटाबेस का उपयोग करते हुए यहां एक त्वरित डेमो दिया गया है।
एक सूचकांक बनाएँ:
CREATE INDEX ix_yourmom ON dbo.Users (Reputation) INCLUDE (Id, DisplayName);
GO
एक इंडेक्स हिंट के साथ एक संग्रहीत कार्यविधि बनाएं जो एक इंडेक्स को इंगित करता है जो मौजूद नहीं है, ब्रंचेड कोड में।
CREATE OR ALTER PROCEDURE dbo.YourMom (@Reputation INT)
AS
BEGIN
IF @Reputation = 1
BEGIN
SELECT u.Id, u.DisplayName, u.Reputation
FROM dbo.Users AS u WITH (INDEX = PK_Users_Id)
WHERE u.Reputation = @Reputation;
END;
IF @Reputation > 1
BEGIN
SELECT u.Id, u.DisplayName, u.Reputation
FROM dbo.Users AS u WITH (INDEX = ix_yourdad)
WHERE u.Reputation = @Reputation;
END;
END;
यदि मैं उस संग्रहित खरीद को निष्पादित करता हूं जो प्रतिष्ठा = 1 की तलाश में है, तो मुझे एक त्रुटि मिलती है।
EXEC dbo.YourMom @Reputation = 1;
Msg 308, लेवल 16, स्टेट 1, प्रोसीजर योरमॉम, लाइन 14 [बैच स्टार्ट लाइन 32] इंडेक्स 'ix_yourdad' टेबल पर 'dbo.Users' (FROM क्लॉज में निर्दिष्ट) मौजूद नहीं है।
यदि हम सूचकांक नाम को ठीक करते हैं और क्वेरी को फिर से चलाते हैं, तो कैश्ड प्लान इस तरह दिखता है:
अंदर, एक्सएमएल के @Reputation
चर के दो संदर्भ होंगे ।
<ColumnReference Column="@Reputation" ParameterDataType="int" ParameterCompiledValue="(1)" />
थोड़ा सा सरल परीक्षण केवल संग्रहीत खरीद के लिए एक अनुमानित योजना प्राप्त करना होगा। आप ऑप्टिमाइज़र को दोनों रास्तों की खोज करते हुए देख सकते हैं:
और अगर निम्नलिखित निष्पादन पर, पैरामीटर का मूल्य बदल जाता है, तो क्या यह संग्रहीत प्रक्रिया को फिर से संकलित और फिर से कैश करेगा, क्योंकि कोड की एक अलग शाखा को निष्पादित किया जाना चाहिए? (यह प्रश्न संकलित करने के लिए काफी महंगा है।) धन्यवाद
नहीं, यह पहले संकलन के रनटाइम मूल्य को बनाए रखेगा।
यदि हम किसी भिन्न के साथ पुन: निष्पादित करते हैं @Reputation
:
EXEC dbo.YourMom @Reputation = 2;
से वास्तविक योजना :
<ColumnReference Column="@Reputation" ParameterDataType="int" ParameterCompiledValue="(1)" ParameterRuntimeValue="(2)" />
हमारे पास अभी भी 1 का संकलित मूल्य है, लेकिन अब 2 का रनटाइम मान है।
प्लान कैश में, जिसे आप फ्री टूल के साथ देख सकते हैं जैसे मेरी कंपनी विकसित करती है, sp_BlitzCache :
संग्रहीत प्रक्रिया को दो बार बुलाया गया है, और इसमें प्रत्येक कथन को एक बार बुलाया गया है।
तो हमारे पास क्या है? संग्रहीत प्रक्रिया में दोनों प्रश्नों के लिए एक कैश्ड योजना।
यदि आप चाहते हैं शाखायुक्त तर्क की इस तरह, आप उप संग्रहित प्रक्रियाओं कॉल करने के लिए होगा:
CREATE OR ALTER PROCEDURE dbo.YourMom (@Reputation INT)
AS
BEGIN
IF @Reputation = 1
BEGIN
EXEC dbo.Reputation1Query;
END;
IF @Reputation > 1
BEGIN
EXEC dbo.ReputationGreaterThan1Query;
END;
END;
या गतिशील एसक्यूएल:
DECLARE @sql NVARCHAR(MAX) = N''
SET @sql +=
N'
SELECT u.Id, u.DisplayName, u.Reputation
FROM dbo.Users AS u '
IF @Reputation = 1
BEGIN
SET @sql += N' (INDEX = PK_Users_Id)
WHERE u.Reputation = @Reputation;'
END;
IF @Reputation > 1
BEGIN
SET @sql += ' WITH (INDEX = ix_yourmom)
WHERE u.Reputation = @Reputation;'
END;
EXEC sys.sp_executesql @sql;
उम्मीद है की यह मदद करेगा!