SQL Server 2016 CTP 2.1には、CTP2.0以降に登場した新しいオブジェクトsys.dm_exec_function_statsが1つあります。これは、sys.dm_exec_procedure_stats、sys.dm_exec_query_stats、およびsys.dm_exec_trigger_statsと同様の機能を提供することを目的としています。 これで、ユーザー定義関数の集計ランタイムメトリックを追跡できるようになりました。
それとも?
少なくともCTP2.1では、ここでは通常のスカラー関数に対して意味のあるメトリックを導出することしかできませんでした。インラインまたはマルチステートメントTVFには何も登録されていませんでした。とにかく実行前に本質的に拡張されるので、インライン関数については驚かない。しかし、マルチステートメントTVFはパフォーマンスの問題であることが多いため、それらも表示されることを期待していました。それらはまだ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;をプライムします
スカラーUDF、マルチステートメントのテーブル値関数、およびインラインテーブル値関数を調査したときに何が起こるか、およびそれぞれの場合にどのような作業が行われたかをどのように確認するかを比較したいと思いました。まず、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の作業によって影響を受けるのを防ぎます。リマインダーのMikael Erikssonに感謝します。)
>多くの場合、その変換を関数に変換する人がいます。これは、次のようにスカラーまたはTVFにすることができます。
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_
あなたが見ている慣習は、私が良い考えだと思う新しいものではありません。それは、DMV内のこれらすべてのクエリを収集されている他のすべてから分離できる最も簡単な方法でした。また、ストアドプロシージャ内のクエリとアドホックバージョンを簡単に区別するために、サフィックスを簡単に追加できるようになりました。)
次に、タイミングを格納する#tempテーブルを作成し、このプロセスを繰り返しました(ストアドプロシージャを2回実行し、プロシージャの本体を分離されたアドホッククエリとして2回実行し、それぞれのタイミングを追跡します):
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
これは驚くべき結果ではありません。スカラー関数を使用すると、パフォーマンスが大幅に低下しますが、マルチステートメントTVFは約4倍悪化しました。複数のテストにわたって、インライン関数は、関数がまったくない場合よりも常に同じか1ミリ秒または2秒高速でした。
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
ここで注意すべき重要な点は、マルチステートメントTVFのINSERTとスカラー関数のRETURNステートメントの時間(ミリ秒)も個々のSELECT内で考慮されるため、すべてを合計するだけでは意味がないということです。タイミング。
手動タイミング
そして最後に、#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
ここでの追加の興味深い結果:プロシージャラッパーには常にある程度のオーバーヘッドがありましたが、それがどれほど重要であるかは本当に主観的かもしれません。
概要
今日の私のポイントは、新しいDMVの動作を示し、期待値を正しく設定することでした。関数のパフォーマンスメトリックの中には、誤解を招くものもあれば、まったく利用できないものもあります(または、少なくとも自分でつなぎ合わせるのは非常に面倒です)。 )。
ただし、この新しいDMVは、SQL Serverが以前に欠落していたクエリ監視の最大の部分の1つをカバーしていると思います。スカラー関数は、使用法を識別する唯一の信頼できる方法がクエリテキストを解析することであったため、パフォーマンスを低下させることがあります。絶対確実というわけではありません。それではパフォーマンスへの影響を分離できないという事実や、そもそもクエリテキストでスカラーUDFを探していることを知っている必要があるという事実を気にしないでください。
付録
スクリプトを添付しました: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にある列