私が担当しているデータベースのクエリの状態を示す次のクエリがあります(ただし、私はDBAではありません)。
SELECT
T3.FullStatement as FullSQLStatement
,T3.ExecutingStatement
,req.session_id as SessionId
,T2.login_name as LoginName
,command as SQLCommand
,start_time as StartTime
,DateDiff(MINUTE,start_time,GetDate()) as ElapsedTimeMinutes
,req.status as QueryStatus
,req.wait_type as WaitType
,req.wait_time as WaitTimeMs
,blocking_session_id as BlockingSessionId
,req.row_count as [RowCount]
,req.cpu_time as CpuTimeMs
,req.total_elapsed_time as TotalElapsedTimeMs
,SubString(sqltext.TEXT,req.statement_start_offset,req.statement_end_offset-req.statement_start_offset)
FROM sys.dm_exec_requests req
Inner Join sys.dm_exec_sessions T2 ON T2.session_id = req.session_id
Cross Apply dbo.GetExecutingSQLStatement (req.session_id) T3
Cross Apply sys.dm_exec_sql_text(sql_handle) AS sqltext
where req.database_id = 5
Order By 6 Desc
これは、部分的には次のような出力を生成します。
含めた例ではうまく表示されていませんが、start_timeはステートメント全体の開始時間であり、ステートメントの実行部分ではありません。完全なステートメントの開始時間とともに実行部分の開始時間を取得できる場所はありますか?完全なステートメントには個別のクエリが多数含まれる可能性があるため、これは私にとって重要です。
現時点では、これは取得する可能性のある値のようには見えません。これは、持っていると便利な値のように見えるため、残念です。
わかりました(ほとんど)。 sys.dm_exec_query_stats DMVには_last_execution_time
_フィールドがありますが、このDMVには次の警告が付属しています。
sys.dm_exec_query_statsの初期クエリは、サーバーで現在実行中のワークロードがある場合、不正確な結果を生成する可能性があります。クエリを再実行することで、より正確な結果を判断できます。
また、_last_execution_time
_はクエリバッチごとであり、ではないため、_sys.dm_exec_query_stats
_の値が複数のセッションにわたってまったく同じSQLの複数の同時実行によってどのように影響を受けるかはわかりませんセッションごと。
以下はこれまでのところです。クリーンアップしたいことが1つあるかもしれませんが、これは_sys.dm_exec_query_stats
_に対応するエントリがないバッチ内の最初のクエリをすでに説明しているはずです(理想的には、常にではありませんが方法)現在のステートメント/クエリが完了した後。また、単一クエリのバッチでも機能するようですので、試してみてください。
_SELECT req.session_id AS [SessionID],
req.start_time AS [BatchStartTime],
req.total_elapsed_time as [BatchMilliseconds], --[TotalElapsedTimeMs],
CASE WHEN stat.last_execution_time IS NOT NULL THEN
DATEADD(MILLISECOND,
(stat.last_elapsed_time / 1000.0),
stat.last_execution_time)
ELSE req.start_time END AS [StatementStartTime],
DATEDIFF(MILLISECOND,
CASE WHEN stat.last_execution_time IS NOT NULL THEN
DATEADD(MILLISECOND, (stat.last_elapsed_time / 1000.0),
stat.last_execution_time)
ELSE req.start_time END, GETDATE()) AS [StatementMilliseconds],
T2.login_name AS [LoginName],
req.command AS [SQLCommand],
req.[status] AS [QueryStatus],
req.wait_type AS [WaitType],
req.wait_time AS [WaitTimeMs],
blocking_session_id AS [BlockingSessionId],
req.row_count AS [RowCount],
req.cpu_time AS [CpuTimeMs],
sqltext.[text] AS [QueryBatch],
SUBSTRING(sqltext.[text],
req.statement_start_offset / 2,
CASE req.statement_end_offset
WHEN -1 THEN DATALENGTH(sqltext.[text])
ELSE (req.statement_end_offset - req.statement_start_offset) / 2
END) AS [CurrentQuery]
FROM sys.dm_exec_requests req
INNER JOIN sys.dm_exec_sessions T2
ON T2.session_id = req.session_id
LEFT JOIN sys.dm_exec_query_stats stat
ON stat.[sql_handle] = req.[sql_handle]
AND stat.statement_end_offset = (req.statement_start_offset - 2)
CROSS APPLY sys.dm_exec_sql_text(req.[sql_handle]) sqltext
-- WHERE req.session_id = 56
ORDER BY req.start_time;
_
私はあなたのクエリ(少し変更された)と次のSQLを別のタブ/セッション(TOP(1)
、TOP(2)
など)、および_10.1
_、_10.2
_などは、WAITFOR
の時点で、現在のステートメントフィールドを見たときに、どのステートメントが処理されているかを簡単に確認できるようにします)。
_SELECT GETDATE() AS [StartTime];
GO
SELECT TOP(1) [name] FROM sys.objects;
WAITFOR DELAY '00:00:10.1';
SELECT TOP(2) [name] FROM sys.objects;
WAITFOR DELAY '00:00:10.2';
SELECT TOP(3) [name] FROM sys.objects;
WAITFOR DELAY '00:00:10.3';
SELECT TOP(4) [name] FROM sys.objects;
WAITFOR DELAY '00:00:10.4';
_
次に、クエリを数回実行するだけで、_dm_exec_requests.start_time
_と_dm_exec_sessions.last_request_start_time
_が次のようになることは明らかです。
私はCROSS APPLY sys.dm_exec_text_query_plan(req.plan_handle, req.statement_end_offset, req.statement_end_offset) tplan
を介して実行プランを取得しようとしましたが、それはNULL
であったため、あまり役に立ちませんでした。
クエリでテストするために、最初の2つの列と_dbo.GetExecutingSQLStatement
_関数への参照を削除する必要がありました。これはおそらく、このクエリにCROSS APPLY sys.dm_exec_sql_text(req.[sql_handle])
を介してすでにロジックがあるため、取り除くこともできるものです。次の3つの変更を行うだけです。
_T3.FullStatement
_(選択フィールド#1)は_sqltext.[text]
_になります
_T3.ExecutingStatement
_(選択フィールド#2)はSUBSTRING(sqltext.[text], req.statement_start_offset / 2, CASE req.statement_end_offset WHEN -1 THEN LEN(sqltext.[text]) ELSE (req.statement_end_offset - req.statement_start_offset) / 2 END)
になります
SUBSTRING
(現在の最後のフィールド)を削除します。 SUBSTRING
を注意深く見れば、私は真上に提案しているのですが、それは基本的に最後に持っていたものであり、2つの誤りが修正されることを期待しています。
statement_end_offset
_は_-1
_であり、部分文字列はエラーになりますしかし、私は余談です。