SQL सर्वर 2016 CTP 2.1 में, एक नया ऑब्जेक्ट है जो CTP 2.0 के बाद दिखाई दिया:sys.dm_exec_function_stats। इसका उद्देश्य sys.dm_exec_procedure_stats, sys.dm_exec_query_stats, और sys.dm_exec_trigger_stats को समान कार्यक्षमता प्रदान करना है। इसलिए अब उपयोगकर्ता-परिभाषित कार्यों के लिए समग्र रनटाइम मेट्रिक्स को ट्रैक करना संभव है।
या है?
सीटीपी 2.1 में कम से कम, मैं केवल नियमित स्केलर कार्यों के लिए यहां कोई सार्थक मीट्रिक प्राप्त कर सकता था - इनलाइन या मल्टी-स्टेटमेंट टीवीएफ के लिए कुछ भी पंजीकृत नहीं था। मैं इनलाइन कार्यों के बारे में आश्चर्यचकित नहीं हूं, क्योंकि वे वैसे भी निष्पादन से पहले अनिवार्य रूप से विस्तारित होते हैं। लेकिन चूंकि मल्टी-स्टेटमेंट टीवीएफ अक्सर प्रदर्शन की समस्याएं होती हैं, मैं उम्मीद कर रहा था कि वे भी दिखाई देंगे। वे अभी भी sys.dm_exec_query_stats में दिखाई देते हैं, इसलिए आप अभी भी वहां से उनके प्रदर्शन मीट्रिक प्राप्त कर सकते हैं, लेकिन जब आपके पास वास्तव में कई कथन हैं जो काम के कुछ हिस्से को निष्पादित करते हैं तो एकत्रीकरण करना मुश्किल हो सकता है - आपके लिए कुछ भी रोल अप नहीं किया गया है।
आइए एक त्वरित नज़र डालें कि यह कैसे खेलता है। मान लें कि हमारे पास 100,000 पंक्तियों वाली एक साधारण तालिका है:
SELECT TOP (100000) o1.[object_id], o1.create_date INTO dbo.src FROM sys.all_objects AS o1 CROSS JOIN sys.all_objects AS o2 ORDER BY o1.[object_id]; GO CREATE CLUSTERED INDEX x ON dbo.src([object_id]); GO -- prime the cache SELECT [object_id], create_date FROM dbo.src;
मैं तुलना करना चाहता था कि क्या होता है जब हम स्केलर यूडीएफ, बहु-कथन तालिका-मूल्यवान कार्यों, और इनलाइन तालिका-मूल्यवान कार्यों की जांच करते हैं, और हम कैसे देखते हैं कि प्रत्येक मामले में क्या काम किया गया था। सबसे पहले, कुछ तुच्छ कल्पना करें जो हम SELECT
. में कर सकते हैं खंड, लेकिन हो सकता है कि हम किसी तारीख को एक स्ट्रिंग के रूप में स्वरूपित करना चाहते हों:
CREATE PROCEDURE dbo.p_dt_Standard @dt_ CHAR(10) = NULL AS BEGIN SET NOCOUNT ON; SELECT @dt_ = CONVERT(CHAR(10), create_date, 120) FROM dbo.src ORDER BY [object_id]; END GO
(मैं आउटपुट को एक वेरिएबल को असाइन करता हूं, जो पूरी तालिका को स्कैन करने के लिए बाध्य करता है, लेकिन प्रदर्शन मेट्रिक्स को SSMS के आउटपुट को उपभोग और प्रस्तुत करने के प्रयासों से प्रभावित होने से रोकता है। रिमाइंडर के लिए धन्यवाद, मिकेल एरिक्सन।)
कई बार आप देखेंगे कि लोग उस रूपांतरण को एक फ़ंक्शन में डालते हैं, और यह स्केलर या टीवीएफ हो सकता है, जैसे:
CREATE FUNCTION dbo.dt_Inline(@dt_ DATETIME) RETURNS TABLE AS RETURN (SELECT dt_ = CONVERT(CHAR(10), @dt_, 120)); GO CREATE FUNCTION dbo.dt_Multi(@dt_ DATETIME) RETURNS @t TABLE(dt_ CHAR(10)) AS BEGIN INSERT @t(dt_) SELECT CONVERT(CHAR(10), @dt_, 120); RETURN; END GO CREATE FUNCTION dbo.dt_Scalar(@dt_ DATETIME) RETURNS CHAR(10) AS BEGIN RETURN (SELECT CONVERT(CHAR(10), @dt_, 120)); END GO
मैंने इन कार्यों के चारों ओर प्रक्रिया रैपर निम्नानुसार बनाए हैं:
CREATE PROCEDURE dbo.p_dt_Inline @dt_ CHAR(10) = NULL AS BEGIN SET NOCOUNT ON; SELECT @dt_ = dt.dt_ FROM dbo.src AS o CROSS APPLY dbo.dt_Inline(o.create_date) AS dt ORDER BY o.[object_id]; END GO CREATE PROCEDURE dbo.p_dt_Multi @dt_ CHAR(10) = NULL AS BEGIN SET NOCOUNT ON; SELECT @dt_ = dt.dt_ FROM dbo.src CROSS APPLY dbo.dt_Multi(create_date) AS dt ORDER BY [object_id]; END GO CREATE PROCEDURE dbo.p_dt_Scalar @dt_ CHAR(10) = NULL AS BEGIN SET NOCOUNT ON; SELECT @dt_ = dt = dbo.dt_Scalar(create_date) FROM dbo.src ORDER BY [object_id]; END GO
(और नहीं, dt_
सम्मेलन जो आप देख रहे हैं वह कुछ नई बात नहीं है, मुझे लगता है कि यह एक अच्छा विचार है, यह सबसे आसान तरीका था जिससे मैं इन सभी प्रश्नों को डीएमवी में एकत्र की जा रही हर चीज से अलग कर सकता था। इसने प्रत्ययों को जोड़ना भी आसान बना दिया ताकि संग्रहीत कार्यविधि और तदर्थ संस्करण के अंदर की क्वेरी के बीच आसानी से अंतर किया जा सके।)
इसके बाद, मैंने समय को स्टोर करने के लिए एक #temp तालिका बनाई, और इस प्रक्रिया को दोहराया (दोनों संग्रहीत प्रक्रिया को दो बार निष्पादित करना, और प्रक्रिया के मुख्य भाग को एक अलग तदर्थ क्वेरी के रूप में दो बार निष्पादित करना, और प्रत्येक के समय को ट्रैक करना):पी>
CREATE TABLE #t ( ID INT IDENTITY(1,1), q VARCHAR(32), s DATETIME2, e DATETIME2 ); GO INSERT #t(q,s) VALUES('p Standard',SYSDATETIME()); GO EXEC dbo.p_dt_Standard; GO 2 UPDATE #t SET e = SYSDATETIME() WHERE ID = 1; GO INSERT #t(q,s) VALUES('ad hoc Standard',SYSDATETIME()); GO DECLARE @dt_st CHAR(10); SELECT @dt_st = CONVERT(CHAR(10), create_date, 120) FROM dbo.src ORDER BY [object_id]; GO 2 UPDATE #t SET e = SYSDATETIME() WHERE ID = 2; GO -- repeat for inline, multi and scalar versions
फिर मैंने कुछ नैदानिक प्रश्न पूछे, और ये रहे परिणाम:
sys.dm_exec_function_stats
SELECT name = OBJECT_NAME(object_id), execution_count, time_milliseconds = total_elapsed_time/1000 FROM sys.dm_exec_function_stats WHERE database_id = DB_ID() ORDER BY name;
परिणाम:
name execution_count time_milliseconds --------- --------------- ----------------- dt_Scalar 400000 1116
यह एक टाइपो नहीं है; केवल अदिश UDF नए DMV में कोई उपस्थिति दिखाता है।
sys.dm_exec_procedure_stats
SELECT name = OBJECT_NAME(object_id), execution_count, time_milliseconds = total_elapsed_time/1000 FROM sys.dm_exec_procedure_stats WHERE database_id = DB_ID() ORDER BY name;
परिणाम:
name execution_count time_milliseconds ------------- --------------- ----------------- p_dt_Inline 2 74 p_dt_Multi 2 269 p_dt_Scalar 2 1063 p_dt_Standard 2 75
यह आश्चर्यजनक परिणाम नहीं है:स्केलर फ़ंक्शन का उपयोग करने से ऑर्डर-ऑफ-परिमाण प्रदर्शन जुर्माना होता है, जबकि मल्टी-स्टेटमेंट टीवीएफ केवल 4x खराब था। कई परीक्षणों में, इनलाइन फ़ंक्शन हमेशा तेज़ या मिलीसेकंड या बिना किसी फ़ंक्शन की तुलना में दो तेज़ था।
sys.dm_exec_query_stats
SELECT query = SUBSTRING([text],s,e), execution_count, time_milliseconds FROM ( SELECT t.[text], s = s.statement_start_offset/2 + 1, e = COALESCE(NULLIF(s.statement_end_offset,-1),8000)/2, s.execution_count, time_milliseconds = s.total_elapsed_time/1000 FROM sys.dm_exec_query_stats AS s OUTER APPLY sys.dm_exec_sql_text(s.[sql_handle]) AS t WHERE t.[text] LIKE N'%dt[_]%' ) AS x;
काटे गए परिणाम, मैन्युअल रूप से पुन:क्रमित:
query (truncated) execution_count time_milliseconds -------------------------------------------------------------------- --------------- ----------------- -- p Standard: SELECT @dt_ = CONVERT(CHAR(10), create_date, 120) ... 2 75 -- ad hoc Standard: SELECT @dt_st = CONVERT(CHAR(10), create_date, 120) ... 2 72 -- p Inline: SELECT @dt_ = dt.dt_ FROM dbo.src AS o CROSS APPLY dbo.dt_Inline... 2 74 -- ad hoc Inline: SELECT @dt_in = dt.dt_ FROM dbo.src AS o CROSS APPLY dbo.dt_Inline... 2 72 -- all Multi: INSERT @t(dt_) SELECT CONVERT(CHAR(10), @dt_, 120); 184 5 -- p Multi: SELECT @dt_ = dt.dt_ FROM dbo.src CROSS APPLY dbo.dt_Multi... 2 270 -- ad hoc Multi: SELECT @dt_m = dt.dt_ FROM dbo.src AS o CROSS APPLY dbo.dt_Multi... 2 257 -- all scalar: RETURN (SELECT CONVERT(CHAR(10), @dt_, 120)); 400000 581 -- p Scalar: SELECT @dt_ = dbo.dt_Scalar(create_date)... 2 986 -- ad hoc Scalar: SELECT @dt_sc = dbo.dt_Scalar(create_date)... 2 902चुनें
यहां ध्यान देने वाली एक महत्वपूर्ण बात यह है कि मल्टी-स्टेटमेंट टीवीएफ में INSERT के लिए मिलीसेकंड में समय और स्केलर फ़ंक्शन में रिटर्न स्टेटमेंट का भी अलग-अलग चयनों के भीतर हिसाब लगाया जाता है, इसलिए इसका कोई मतलब नहीं है कि सभी को जोड़ दें समय।
मैन्युअल समय
और फिर अंत में, #temp तालिका से समय:
SELECT query = q, time_milliseconds = DATEDIFF(millisecond, s, e) FROM #t ORDER BY ID;
परिणाम:
query time_milliseconds --------------- ----------------- p Standard 107 ad hoc Standard 78 p Inline 80 ad hoc Inline 78 p Multi 351 ad hoc Multi 263 p Scalar 992 ad hoc Scalar 907
यहां अतिरिक्त दिलचस्प परिणाम:प्रक्रिया रैपर में हमेशा कुछ ओवरहेड होता था, हालांकि यह कितना महत्वपूर्ण है वास्तव में व्यक्तिपरक हो सकता है।
सारांश
आज मेरा मुद्दा केवल नए डीएमवी को कार्रवाई में दिखाने के लिए था, और उम्मीदों को सही ढंग से सेट करना था - कार्यों के लिए कुछ प्रदर्शन मीट्रिक अभी भी भ्रामक होंगे, और कुछ अभी भी उपलब्ध नहीं होंगे (या कम से कम अपने लिए एक साथ टुकड़े करने के लिए बहुत कठिन हो सकते हैं )
मुझे लगता है कि यह नया डीएमवी क्वेरी मॉनिटरिंग के सबसे बड़े टुकड़ों में से एक को कवर करता है जो SQL सर्वर पहले गायब था, हालांकि:स्केलर फ़ंक्शन कभी-कभी अदृश्य प्रदर्शन हत्यारे होते हैं, क्योंकि उनके उपयोग की पहचान करने का एकमात्र विश्वसनीय तरीका क्वेरी टेक्स्ट को पार्स करना था, जो मूर्खता से दूर है। इस तथ्य पर ध्यान न दें कि यह आपको प्रदर्शन पर उनके प्रभाव को अलग करने की अनुमति नहीं देगा, या आपको पहले स्थान पर क्वेरी टेक्स्ट में स्केलर यूडीएफ की तलाश करने के लिए जाना होगा।
परिशिष्ट
मैंने स्क्रिप्ट संलग्न की है:DMExecFunctionStats.zip
साथ ही, CTP1 के अनुसार, यहां स्तंभों का सेट दिया गया है:
database_id | object_id | type | type_desc | |
sql_handle | plan_handle | cached_time | last_execution_time | execution_count |
total_worker_time | last_worker_time | min_worker_time | max_worker_time | |
total_physical_reads | last_physical_reads | min_physical_reads | max_physical_reads | |
total_logical_writes | last_logical_writes | min_logical_writes | max_logical_writes | |
total_logical_reads | last_logical_reads | min_logical_reads | max_logical_reads | |
total_elapsed_time | last_elapsed_time | min_elapsed_time | max_elapsed_time |
वर्तमान में sys.dm_exec_function_stats में कॉलम