क्वेरी प्लान बनाने की लागत कैसे मापें या खोजें?


18

मेरे पास एक विशिष्ट मामला है जहां पैरामीटर सूँघने के कारण "खराब" निष्पादन योजना की योजना में उतरने का कारण बनता है, जिससे मेरी संग्रहीत प्रक्रिया के बाद के निष्पादन बहुत धीमा हो जाते हैं। मैं स्थानीय चर के साथ इस समस्या को "हल" कर सकता हूं OPTIMIZE FOR ... UNKNOWN, और OPTION(RECOMPILE)। हालांकि, मैं क्वेरी में गोता लगा सकता हूं और इसे अनुकूलित करने का प्रयास कर सकता हूं।

मैं यह निर्धारित करने की कोशिश कर रहा हूं कि मुझे क्या करना चाहिए : समस्याओं को ठीक करने के लिए सीमित समय दिया गया है मैं इसे नहीं करने की लागत जानना चाहूंगा । जैसा कि मैंने देखा है, अगर मैं बस के साथ रहना OPTION(RECOMPILE), शुद्ध प्रभाव यह है कि एक क्वेरी योजना हर बार क्वेरी रन होने पर फिर से बनाया जाता है। इसलिए, मुझे लगता है कि मुझे पता होना चाहिए:

कैसे पता करें कि क्वेरी प्लान बनाने की लागत क्या है?

अपने स्वयं के प्रश्न का उत्तर देने के लिए, मैंने Googled (जैसे इस क्वेरी के साथ ), और मैं dm_exec_query_statsDMV के लिए कॉलम के प्रलेखन से गुजरा हूँ । मैंने इस जानकारी को खोजने के लिए "वास्तविक क्वेरी योजना" के लिए SSMS में आउटपुट विंडो का निरीक्षण किया है। अंत में, मैंने DBA.SE खोजा है । उनमें से कोई भी एक जवाब के लिए नेतृत्व किया।

क्या कोई मुझे बता सकता है? क्या योजना निर्माण के लिए ओटी को खोजना या मापना संभव समय है?


5
मैं बिन्यामीन नेवरेज़ द्वारा एसक्यूएल सर्वर क्वेरी ऑप्टिमाइज़र के अंदर की एक प्रति हथियाने की सलाह दूंगा । यह मुफ़्त है। अध्याय 5 'अनुकूलन प्रक्रिया' आपको अपनी क्वेरी के संकलन समय को पूरा करने में मदद कर सकती है। बहुत कम से कम, यह इस बारे में जानकारीपूर्ण है कि क्वेरी प्लान बनाने के लिए ऑप्टिमाइज़र किस माध्यम से जाता है।
मार्क सिनकिंसन

जवाबों:


18

कैसे पता करें कि क्वेरी प्लान बनाने की लागत क्या है?

आप उदाहरण के लिए, क्वेरी प्लान में रूट नोड के गुणों को देख सकते हैं:

रूट गुण निकालते हैं
(मुक्त संतरी एक योजना एक्सप्लोरर से स्क्रीनशॉट )

यह जानकारी योजना कैश की क्वेरी के द्वारा भी उपलब्ध है, उदाहरण के लिए निम्नलिखित रिश्तों के आधार पर एक प्रश्न का उपयोग कर:

WITH XMLNAMESPACES (DEFAULT 'http://schemas.microsoft.com/sqlserver/2004/07/showplan')
SELECT 
    CompileTime = c.value('(QueryPlan/@CompileTime)[1]', 'int'),
    CompileCPU = c.value('(QueryPlan/@CompileCPU)[1]', 'int'),
    CompileMemory = c.value('(QueryPlan/@CompileMemory)[1]', 'int'),
    ST.[text],
    QP.query_plan
FROM sys.dm_exec_cached_plans AS CP
CROSS APPLY sys.dm_exec_query_plan(CP.plan_handle) AS QP
CROSS APPLY sys.dm_exec_sql_text(CP.plan_handle) AS ST
CROSS APPLY QP.query_plan.nodes('ShowPlanXML/BatchSequence/Batch/Statements/StmtSimple') AS N(c);

परिणाम टुकड़े

इन प्रकार के प्रश्नों को संभालने के लिए आपके पास जो विकल्प हैं, उनके पूर्ण उपचार के लिए, Erland Sommarskog के हाल ही में अपडेट किए गए लेख को देखें


4

मान लेना "लागत" समय के संदर्भ में है (हालांकि यह सुनिश्चित नहीं है कि ;-) के संदर्भ में यह और क्या हो सकता है, फिर बहुत कम से कम आपको निम्नलिखित की तरह कुछ करके इसकी भावना प्राप्त करने में सक्षम होना चाहिए:

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 का उपयोग तब तक नहीं किया जाता था जब तक कि यह किसी विशेष क्वेरी के लिए आवश्यक न हो।

  1. यदि संग्रहीत कार्यविधि के लिए कई इनपुट पैरामीटर हैं, तो उन आंकड़ों का पता लगाएं, जिनका उपयोग स्तंभों के साथ किया जाता है जिनके डेटा वितरण में बहुत अधिक अंतर होता है (और इसलिए इस समस्या का कारण बनता है) और उन लोगों का उपयोग उन स्तंभों के साथ किया जाता है जिनके पास और भी अधिक वितरण हैं (और नहीं होना चाहिए) इस समस्या के कारण)।

  2. समान रूप से वितरित स्तंभों के साथ जुड़े रहे हैं जो खरीद इनपुट परम के लिए मापदंडों का उपयोग कर गतिशील SQL स्ट्रिंग बनाएँ। यह मानदंड इस क्वेरी से संबंधित कैश में निष्पादन योजनाओं में परिणामी वृद्धि को कम करने में मदद करता है।

  3. शेष मापदंडों के लिए जो अत्यधिक विविध वितरणों से जुड़े हैं, उन्हें गतिशील एसक्यूएल में शाब्दिक मूल्यों के रूप में संक्षिप्त किया जाना चाहिए। चूंकि एक अद्वितीय क्वेरी क्वेरी टेक्स्ट के किसी भी परिवर्तन से निर्धारित होती है WHERE StatusID = 1, इसलिए होने की तुलना में एक अलग क्वेरी है, और इसलिए, अलग क्वेरी प्लान है WHERE StatusID = 2

  4. यदि कोई भी खरीद इनपुट पैरामीटर, जिसे क्वेरी के पाठ में समाप्‍त किया जाना है, तो तार हैं, और SQL इंजेक्शन से बचाने के लिए इनका सत्यापन करने की आवश्‍यकता है (हालाँकि ऐसा तब होने की संभावना कम है जब तार द्वारा पारित किया जा रहा हो। एप्लिकेशन और एक उपयोगकर्ता नहीं है, लेकिन अभी भी)। कम से कम यह REPLACE(@Param, '''', '''''')सुनिश्चित करने के लिए कि एकल-उद्धरण एकल-उद्धरण से बच गए हैं।

  5. यदि आवश्यक हो, तो एक प्रमाण पत्र बनाएं जिसका उपयोग उपयोगकर्ता बनाने और संग्रहीत प्रक्रिया पर हस्ताक्षर करने के लिए किया जाएगा, जैसे कि प्रत्यक्ष तालिका अनुमतियाँ केवल नए प्रमाणपत्र-आधारित उपयोगकर्ता को दी जाएंगी और उन [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;

उत्तर देने के लिए (काफी कुछ) समय देने के लिए धन्यवाद! मैं कैसे संकलन समय प्राप्त करने के बारे पहली बिट के बारे में थोड़ा उलझन में हालांकि हूँ, यह देखते हुए कि यह एक कारक है 3 परिणाम मैं का उपयोग करके प्राप्त की तुलना में कम @ PaulWhite का दृष्टिकोण । - डायनेमिक एसक्यूएल बिट पर दूसरा दिलचस्प है (हालांकि इसे लागू करने के लिए भी समय की आवश्यकता होगी; कम से कम OPTIONमेरी क्वेरी पर केवल थप्पड़ मारने से अधिक ), और मुझे बहुत ज्यादा चोट नहीं पहुंचेगी क्योंकि यह स्पोक एकीकरण परीक्षणों में अच्छी तरह से उपयोग किया जाता है। - किसी भी मामले में: अपनी अंतर्दृष्टि के लिए धन्यवाद!
जेरोइन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.