SQL Serverには、実行中のストアドプロシージャに渡されるパラメーターの値を決定する方法があります


13

実行中のストアドプロシージャを決定する1つの方法は、次のような「動的管理」メソッドを使用することです。

SELECT 
    sqlText.Text, req.* 
FROM 
    sys.dm_exec_requests req
OUTER APPLY 
    sys.dm_exec_sql_text(req.sql_handle) AS sqltext

ただし、これはストアドプロシージャのcreateステートメントのテキストのみを表示します。例えば:

CREATE PROCEDURE IMaProcedure @id int AS SELECT * FROM AllTheThings Where id = @id

理想的には、問題のあるパラメーターの特定のセットに対して非常に長く実行する原因となっている実行中のプロシージャーのパラメーターを確認したいと思います。

それを行う方法はありますか?(この質問では、 Aaron BertrandDBCC InputBufferについて言及していますが、この問題には適切ではないと思います。)


入力パラメータをキャプチャする、または実行時に渡されたものを確認する唯一の方法は、値とログファイルの呼び出しを記録することです。これをエラーログで確認したい場合はRAISEERRORを使用して簡単に実行できます。または、もう少し手間をかけて、外部ファイルに書き込みます。
スティーブMangiameli

回答:


16

この情報(ストアドプロシージャ(RPC呼び出しなど)またはパラメーター化されたクエリに渡される実行時パラメーター値)は、SQLトレースを介してのみ使用できます(SQL Serverの新しいバージョンでは同等の拡張イベントを想定しています)。:あなたは(これはSQL Serverに付属)SQL Serverプロファイラを実行しているとのような様々な「完了」イベントを、選択することで、これを見ることができるRPC:CompletedSP:CompletedSQL:BatchCompleted。また、値がそこにあるため、「TextData」フィールドを選択する必要があります。

この質問に対する私の答えと@Kinの答えの違いは、@ Kinの答え(私が間違えない限り、この場合はこれを削除します)が以下のいずれかに焦点を当てていることです

  • 独自のクエリプラン(この場合、実行時パラメータ情報を含めることができますが、他のセッション/ SPIDについてはできません)、または
  • DMVからの計画(この場合、コンパイルされたパラメーター値のみが必要であり、ランタイム値ではありません)。

私の答えは、現在実行中の他のセッションのパラメーター値を取得することに焦点を当てています。DMVに依存する場合、実行時パラメーター値がコンパイル済みパラメーター値と同じかどうかを知る方法はありません。また、この質問のコンテキストは、他のセッション/ SPID(およびSQL Server 2005では拡張イベントがSQL Server 2008で導入されたのに対し)を介して送信されるクエリのランタイム値を追跡することです。


13

あなたはできる実際の実行計画をオンにしてから実行計画のXMLを見てください。

ここに画像の説明を入力してください

または、SQLセントリーのプランエクスプローラーツールを使用parameterscompiled valuerun time value、実際の実行プランを一覧表示するタブを確認できます。

実際のプランをオンにできない場合は、以下で説明するようにプランキャッシュを調べることができます。

-- borrowed from  Erland Sommarskog
-- Link : http://www.sommarskog.se/query-plan-mysteries.html#dmvgettingplans
-- Remember that you are looking at the estimated plan so the actual no. of rows and actual executions wont be there ! <-- Important why a particular plan is bad.

DECLARE @dbname    nvarchar(256),
        @procname  nvarchar(256)
SELECT @dbname = 'Northwind',  -- Your DB name
       @procname = 'dbo.List_orders_11' -- The SP that you want to get parameters for !

; WITH basedata AS (
   SELECT qs.statement_start_offset/2 AS stmt_start,
          qs.statement_end_offset/2 AS stmt_end,
          est.encrypted AS isencrypted, est.text AS sqltext,
          epa.value AS set_options, qp.query_plan,
          charindex('<ParameterList>', qp.query_plan) + len('<ParameterList>')
             AS paramstart,
          charindex('</ParameterList>', qp.query_plan) AS paramend
   FROM   sys.dm_exec_query_stats qs
   CROSS  APPLY sys.dm_exec_sql_text(qs.sql_handle) est
   CROSS  APPLY sys.dm_exec_text_query_plan(qs.plan_handle,
                                            qs.statement_start_offset,
                                            qs.statement_end_offset) qp
   CROSS  APPLY sys.dm_exec_plan_attributes(qs.plan_handle) epa
   WHERE  est.objectid  = object_id (@procname)
     AND  est.dbid      = db_id(@dbname)
     AND  epa.attribute = 'set_options'
), next_level AS (
   SELECT stmt_start, set_options, query_plan,
          CASE WHEN isencrypted = 1 THEN '-- ENCRYPTED'
               WHEN stmt_start >= 0
               THEN substring(sqltext, stmt_start + 1,
                              CASE stmt_end
                                   WHEN 0 THEN datalength(sqltext)
                                   ELSE stmt_end - stmt_start + 1
                              END)
          END AS Statement,
          CASE WHEN paramend > paramstart
               THEN CAST (substring(query_plan, paramstart,
                                   paramend - paramstart) AS xml)
          END AS params
   FROM   basedata
)
SELECT set_options AS [SET], n.stmt_start AS Pos, n.Statement,
       CR.c.value('@Column', 'nvarchar(128)') AS Parameter,
       CR.c.value('@ParameterCompiledValue', 'nvarchar(128)') AS [Sniffed Value],
       CAST (query_plan AS xml) AS [Query plan]
FROM   next_level n
CROSS  APPLY   n.params.nodes('ColumnReference') AS CR(c)
ORDER  BY n.set_options, n.stmt_start, Parameter

5
プランキャッシュには、後で実行される特定の実行の値ではなく、コンパイルされた値のみが含まれます。Showplan XML Statistics ProfileProfilerのイベントを使用して実際の計画を取得することもできますが、Profilerを使用しない場合、これを取得する方法はそれほど多くありません。
マーティンスミス

1

@SolomonRutzkyが正しい。
SQLプロファイラトレースが唯一の方法です(Sprocを編集しないで)。

Sprocを編集します。

ただし、次に最適なのは、問題のSprocをわずかに編集することです。
現在の時刻を先頭にDateTime変数を宣言します。
Sprocの最後に、Sproc_StartTime、Sproc_EndTime、およびパラメーター値をテーブルに記録します。

Sprocの処理に長い時間が使用された場合にのみログに記録するためにDateDiff()を使用する条件ロジックを追加することもできます。
これにより、Sprocの速度が向上し、Sprocがチップトップで実行されているときのログテーブルのスペース消費が削減される場合があります。

その後、数か月にわたってクエリおよび分析できるログファイルがあります(Prodでトレースを実行することなく)。
Sprocのチューニングが完了したら、追加したTimerおよびLoggerロジックの数行を削除するだけです。

キャッシュプランのパラメーター値:

ログテーブルに現在のキャッシュプランパラメーター値を含めると、パフォーマンスの問題を悪化させているかどうかを判断するのに役立ちます。データのスライスとダイシングに使用されることがわかっている場合、Sprocでパラメータを処理する方法を設定するため
に使用OPTIMIZE FORします。オプションのフィルターとしてパラメーターを持つ同じSprocを使用すると、一貫した高速な結果が得られる
ことがわかりました。 それらをどのように処理するかを指定する場合、考慮する変数は間違いなく1つ少なくなります。OPTIMIZE FOR

以下は、Select-Statementの下部に追加できるものの例です。

OPTION(OPTIMIZE FOR (@SiteID = 'ABC',
                     @LocationID = NULL, @DepartmentID = NULL,
                     @EmployeeID = NULL, @CustomerID = NULL,
                     @ProductID = NULL, @OrderID = NULL, @OrderStatusID = NULL,
                     @IncludedCancelledOrders = 1,
                     @StartDate UNKNOWN, @EndDate UNKNOWN))

0

Erland Sommarskogのクエリを使用してプランXMLを細断し、ParameterCompiledValueを引き出すと、CHARINDEX(組み込み関数)が文字列に一致する最初の検索を行うため、最初のCTEがWARNINGS(暗黙の変換など)を含むプランを考慮しないことに気付きました入力(つまり)およびそのような警告は、これらと同じフレーズ/ノードを使用します。

したがって、このセクションを以下の改訂セクションに置き換えることを提案します。

      CHARINDEX('<ParameterList>', qp.query_plan) + LEN('<ParameterList>') AS paramstart,
      CHARINDEX('</ParameterList>', qp.query_plan) AS paramend

改訂セクション:

       CHARINDEX('<ParameterList><ColumnReference', qp.query_plan) + LEN('<ParameterList>') AS paramstart,
       CHARINDEX('</ParameterList></QueryPlan>', qp.query_plan) AS paramend

Disallowed implicit conversion from data type xml to data type varchar, table 'sys.dm_exec_query_plan', column 'query_plan'. Use the CONVERT function to run this query.
マット

-1
SELECT DB_NAME(req.database_id),
sqltext.TEXT,
req.session_id,
req.status,
req.start_time,
req.command,
req.cpu_time,
req.total_elapsed_time ,   REPLACE(REPLACE(REPLACE(REPLACE(
CONVERT(VARCHAR(MAX), CONVERT(XML, REPLACE( query_plan, 'xmlns="','xmlns1="')).query('//        ParameterList/ColumnReference')),
'<ColumnReference Column="','declare '),
'" ParameterDataType="',' '),
'" ParameterCompiledValue="(',' = '),
')"/>', CONCAT(';', CHAR(10) , CHAR(13))) ParameterList
FROM sys.dm_exec_requests req
CROSS APPLY sys.dm_exec_sql_text(sql_handle) AS sqltext 
 CROSS  APPLY sys.dm_exec_text_query_plan(plan_handle, statement_start_offset, statement_end_offset) qp
order by req.total_elapsed_time desc 

2
コードのみの回答は推奨されません。このコードが問題を解決する理由の説明を追加することを検討してください。参照してください。回答する方法
ピーターVandivier
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.