मान लेना "लागत" समय के संदर्भ में है (हालांकि यह सुनिश्चित नहीं है कि ;-) के संदर्भ में यह और क्या हो सकता है, फिर बहुत कम से कम आपको निम्नलिखित की तरह कुछ करके इसकी भावना प्राप्त करने में सक्षम होना चाहिए:
DBCC FREEPROCCACHE WITH NO_INFOMSGS;
SET STATISTICS TIME ON;
EXEC sp_help 'sys.databases'; -- replace with your proc
SET STATISTICS TIME OFF;
"संदेश" टैब में बताई गई पहली वस्तु होनी चाहिए:
SQL सर्वर पार्स और संकलन समय:
मैं इसे कम से कम 10 बार चलाऊंगा और "CPU" और "Elapsed" मिलीसेकंड दोनों को औसत करूंगा।
आदर्श रूप से आप इसे प्रोडक्शन में चलाएंगे ताकि आपको सही समय का अनुमान मिल सके, लेकिन शायद ही कभी लोगों को प्रोडक्शन में प्लान कैश क्लियर करने की अनुमति दी गई हो। सौभाग्य से, SQL Server 2008 में शुरू होने से कैश से एक विशिष्ट योजना को साफ करना संभव हो गया। किस मामले में आप निम्न कार्य कर सकते हैं:
DECLARE @SQL NVARCHAR(MAX) = '';
;WITH cte AS
(
SELECT DISTINCT stat.plan_handle
FROM sys.dm_exec_query_stats stat
CROSS APPLY sys.dm_exec_text_query_plan(stat.plan_handle, 0, -1) qplan
WHERE qplan.query_plan LIKE N'%sp[_]help%' -- replace "sp[_]help" with proc name
)
SELECT @SQL += N'DBCC FREEPROCCACHE ('
+ CONVERT(NVARCHAR(130), cte.plan_handle, 1)
+ N');'
+ NCHAR(13) + NCHAR(10)
FROM cte;
PRINT @SQL;
EXEC (@SQL);
SET STATISTICS TIME ON;
EXEC sp_help 'sys.databases' -- replace with your proc
SET STATISTICS TIME OFF;
हालांकि, पैरामीटर के लिए पारित किए जा रहे मूल्यों की परिवर्तनशीलता के आधार पर "खराब" कैश की गई योजना का कारण बनता है, इस पर विचार करने के लिए एक और तरीका है जो बीच का मैदान है OPTION(RECOMPILE)
और OPTION(OPTIMIZE FOR UNKNOWN)
: डायनेमिक SQL। हाँ, मैंने कहा। और मेरा मतलब है कि गैर-मानकीकृत डायनामिक एसक्यूएल। यहाँ क्यों है।
आपके पास स्पष्ट रूप से डेटा है जो एक असमान वितरण है, कम से कम एक या अधिक इनपुट पैरामीटर मानों के संदर्भ में। उल्लिखित विकल्पों में से निम्न हैं:
OPTION(RECOMPILE)
हर निष्पादन के लिए एक योजना उत्पन्न करेगा और आप कभी भी किसी भी योजना के पुन: उपयोग से लाभ नहीं ले पाएंगे , भले ही पैरामीटर मान फिर से पूर्व चाल (एस) के समान हों। ऐसे प्रोक्स के लिए जिन्हें अक्सर कहा जाता है - एक बार हर कुछ सेकंड या उससे अधिक बार - यह आपको सामयिक भयानक स्थिति से बचाएगा, लेकिन फिर भी आपको हमेशा-हमेशा-नहीं-महान स्थिति में छोड़ देता है।
OPTION(OPTIMIZE FOR (@Param = value))
उस विशेष मूल्य के आधार पर एक योजना तैयार करेगा, जो कई मामलों में मदद कर सकता है लेकिन फिर भी आपको वर्तमान मुद्दे के लिए खुला छोड़ देता है।
OPTION(OPTIMIZE FOR UNKNOWN)
एक औसत वितरण के लिए किन राशियों के आधार पर एक योजना तैयार की जाएगी, जो कुछ प्रश्नों को मदद करेगी लेकिन दूसरों को चोट पहुंचाएगी। यह स्थानीय चर का उपयोग करने के विकल्प के समान होना चाहिए।
डायनेमिक एसक्यूएल, हालांकि, जब सही ढंग से किया जाता है , तो अपने स्वयं के अलग-अलग क्वेरी प्लान को आदर्श (अच्छी तरह से, जितना वे होने वाले हैं) होने के लिए पास किए जाने वाले विभिन्न मूल्यों के लिए अनुमति देगा। यहां मुख्य लागत यह है कि जैसे-जैसे मूल्यों में विविधता आ रही है, कैश में निष्पादन योजनाओं की संख्या बढ़ जाती है, और वे स्मृति को ग्रहण करते हैं। मामूली लागत हैं:
SQL इंजेक्शन को रोकने के लिए स्ट्रिंग मापदंडों को मान्य करने की आवश्यकता है
संभवतः डायनेमिक SQL को प्रत्यक्ष तालिका अनुमतियों की आवश्यकता होने के बाद आदर्श सुरक्षा अमूर्तता बनाए रखने के लिए प्रमाणपत्र और प्रमाणपत्र-आधारित उपयोगकर्ता सेट करने की आवश्यकता होती है।
इसलिए, यहां बताया गया है कि मैंने इस स्थिति को कैसे प्रबंधित किया है जब मेरे पास प्रोक्स थे जिन्हें प्रति सेकंड एक से अधिक बार बुलाया गया था और लाखों पंक्तियों के साथ कई तालिकाओं को मारा गया था। मैंने कोशिश की थी, OPTION(RECOMPILE)
लेकिन 99% मामलों में यह प्रक्रिया के लिए बहुत हानिकारक साबित हुआ, जिसमें पैरामीटर सूँघने / खराब कैश योजना की समस्या नहीं थी। और कृपया ध्यान रखें कि इनमें से एक प्रोक्स में लगभग 15 प्रश्न थे और उनमें से केवल 3 - 5 को डायनेमिक SQL में परिवर्तित किया गया था जैसा कि यहाँ वर्णित है; डायनेमिक SQL का उपयोग तब तक नहीं किया जाता था जब तक कि यह किसी विशेष क्वेरी के लिए आवश्यक न हो।
यदि संग्रहीत कार्यविधि के लिए कई इनपुट पैरामीटर हैं, तो उन आंकड़ों का पता लगाएं, जिनका उपयोग स्तंभों के साथ किया जाता है जिनके डेटा वितरण में बहुत अधिक अंतर होता है (और इसलिए इस समस्या का कारण बनता है) और उन लोगों का उपयोग उन स्तंभों के साथ किया जाता है जिनके पास और भी अधिक वितरण हैं (और नहीं होना चाहिए) इस समस्या के कारण)।
समान रूप से वितरित स्तंभों के साथ जुड़े रहे हैं जो खरीद इनपुट परम के लिए मापदंडों का उपयोग कर गतिशील SQL स्ट्रिंग बनाएँ। यह मानदंड इस क्वेरी से संबंधित कैश में निष्पादन योजनाओं में परिणामी वृद्धि को कम करने में मदद करता है।
शेष मापदंडों के लिए जो अत्यधिक विविध वितरणों से जुड़े हैं, उन्हें गतिशील एसक्यूएल में शाब्दिक मूल्यों के रूप में संक्षिप्त किया जाना चाहिए। चूंकि एक अद्वितीय क्वेरी क्वेरी टेक्स्ट के किसी भी परिवर्तन से निर्धारित होती है WHERE StatusID = 1
, इसलिए होने की तुलना में एक अलग क्वेरी है, और इसलिए, अलग क्वेरी प्लान है WHERE StatusID = 2
।
यदि कोई भी खरीद इनपुट पैरामीटर, जिसे क्वेरी के पाठ में समाप्त किया जाना है, तो तार हैं, और SQL इंजेक्शन से बचाने के लिए इनका सत्यापन करने की आवश्यकता है (हालाँकि ऐसा तब होने की संभावना कम है जब तार द्वारा पारित किया जा रहा हो। एप्लिकेशन और एक उपयोगकर्ता नहीं है, लेकिन अभी भी)। कम से कम यह REPLACE(@Param, '''', '''''')
सुनिश्चित करने के लिए कि एकल-उद्धरण एकल-उद्धरण से बच गए हैं।
यदि आवश्यक हो, तो एक प्रमाण पत्र बनाएं जिसका उपयोग उपयोगकर्ता बनाने और संग्रहीत प्रक्रिया पर हस्ताक्षर करने के लिए किया जाएगा, जैसे कि प्रत्यक्ष तालिका अनुमतियाँ केवल नए प्रमाणपत्र-आधारित उपयोगकर्ता को दी जाएंगी और उन [public]
उपयोगकर्ताओं को नहीं जो अन्यथा ऐसी अनुमतियाँ नहीं होनी चाहिए। ।
उदाहरण proc:
CREATE PROCEDURE MySchema.MyProc
(
@Param1 INT,
@Param2 DATETIME,
@Param3 NVARCHAR(50)
)
AS
SET NOCOUNT ON;
DECLARE @SQL NVARCHAR(MAX);
SET @SQL = N'
SELECT tab.Field1, tab.Field2, ...
FROM MySchema.SomeTable tab
WHERE tab.Field3 = @P1
AND tab.Field8 >= CONVERT(DATETIME, ''' +
CONVERT(NVARCHAR(50), @Param2, 121) +
N''')
AND tab.Field2 LIKE N''' +
REPLACE(@Param3, N'''', N'''''') +
N'%'';';
EXEC sp_executesql
@SQL,
N'@P1 INT',
@P1 = @Param1;