SE の雑記

SQL Server の情報をメインに Microsoft 製品の勉強内容を日々投稿

SQL Database のクエリのトレース方法について

leave a comment

SQL Database は SQL Server プロファイラで接続をすることができないため、SQL Server で使用する機会の多い、プロファイラを用いたクエリのトレースを実施することができません。

データベースエンジンの SQL Server プロファイラを使用したトレースに関しては、今後廃止される予定の機能となっているため、SQL Database 向けに提供されることはないと思います。

SQL Database のクエリのトレース方法については、拡張イベントで実施するのが一般的な方法になるかと。

SQL Database の拡張イベント

SQL Database の拡張イベントですが、データを永続化する場合は、ストレージに保存する形式となりますが、一時的なトレースであれば、リングバッファを使用することもできます。

デバッグ等でクエリを確認すればよいのであれば、リングバッファでもよいかなと思います。

リングバッファを使用したクエリのトレースは以下のようなコマンドで作成することができます。

-- クエリのトレース
CREATE EVENT SESSION [QueryTrace] ON DATABASE 
ADD EVENT sqlserver.rpc_completed(SET collect_statement=(1)
    ACTION(sqlserver.client_app_name,sqlserver.client_hostname,sqlserver.database_name,sqlserver.plan_handle,sqlserver.query_hash,sqlserver.query_hash_signed,sqlserver.query_plan_hash,sqlserver.query_plan_hash_signed,sqlserver.session_id,sqlserver.sql_text,sqlserver.username)
    WHERE ([statement]<>N'exec sp_reset_connection')),
ADD EVENT sqlserver.sp_statement_completed(
    ACTION(sqlserver.client_app_name,sqlserver.client_hostname,sqlserver.database_name,sqlserver.plan_handle,sqlserver.query_hash,sqlserver.query_hash_signed,sqlserver.query_plan_hash,sqlserver.query_plan_hash_signed,sqlserver.session_id,sqlserver.sql_text,sqlserver.username)),
ADD EVENT sqlserver.sql_batch_completed(
    ACTION(sqlserver.client_app_name,sqlserver.client_hostname,sqlserver.database_name,sqlserver.plan_handle,sqlserver.query_hash,sqlserver.query_hash_signed,sqlserver.query_plan_hash,sqlserver.query_plan_hash_signed,sqlserver.session_id,sqlserver.sql_text,sqlserver.username)),
ADD EVENT sqlserver.sql_statement_completed(
    ACTION(sqlserver.client_app_name,sqlserver.client_hostname,sqlserver.database_name,sqlserver.plan_handle,sqlserver.query_hash,sqlserver.query_hash_signed,sqlserver.query_plan_hash,sqlserver.query_plan_hash_signed,sqlserver.session_id,sqlserver.sql_text,sqlserver.username))
ADD TARGET package0.ring_buffer
WITH (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_MULTIPLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=30 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=OFF,STARTUP_STATE=ON)
GO

ALTER EVENT SESSION [QueryTrace] ON DATABASE STATE = START
GO

 

これで、クエリ系の情報を取得するための拡張イベントが作成され、1,000 件程度のイベントを取得することができるかと。

取得されたリングバッファのデータは以下のクエリでアクセスすることができます。

SELECT CAST(target_data AS XML) AS xml_data 
FROM sys.dm_xe_database_session_targets 
WHERE event_session_address = 
(SELECT address FROM sys.dm_xe_database_sessions WHERE name = 'QueryTrace')

 

取得できるデータは XML なので、クエリの情報を確認するためには少し加工したほうが良いかと。

単純に検索してしまうと、低いパフォーマンスレベルではかなり時間がかかってしまったため、以下のようなクエリで取得してみました。


DROP TABLE IF EXISTS #xmldata
GO
CREATE TABLE #xmldata (C1 int IDENTITY PRIMARY KEY, xml_data XML)

INSERT INTO #xmldata (xml_data)
SELECT CAST(target_data AS XML) AS xml_data 
FROM sys.dm_xe_database_session_targets 
WHERE event_session_address = 
(SELECT address FROM sys.dm_xe_database_sessions WHERE name = 'QueryTrace')

CREATE PRIMARY XML INDEX idx_xml on #xmldata (xml_data)

SELECT
	xed.event_data.value('(@timestamp)[1]','datetime2') AS timestamp,  
   xed.event_data.value('(@name)[1]','varchar(255)') AS event_name,
   xed.event_data.value('(action[@name="sql_text"]/value)[1]','nvarchar(max)') AS sql_text,
   xed.event_data.value('(data[@name="statement"]/value)[1]','nvarchar(max)') AS statement,
   xed.event_data.value('(action[@name="username"]/value)[1]','nvarchar(255)') AS username,
   xed.event_data.value('(action[@name="client_hostname"]/value)[1]','nvarchar(255)') AS client_hostname,
   xed.event_data.value('(action[@name="client_app_name"]/value)[1]','nvarchar(max)') AS client_app_name
FROM
	#xmldata
CROSS APPLY xml_data.nodes('//RingBufferTarget/event') AS xed (event_data)

 

Basic で実行した場合、2~3 分程度実行に時間がかかると思いますが、以下のような実行結果を取得できます。

image

今回のクエリでは項目を絞っていますが、SQL Server プロファイラに近い情報はとれているかと。

もう一つの SQL Database のトレースとしては、「query_post_execution_showplan」になります。


-- クエリの進行状況取得用のトレース
CREATE EVENT SESSION [QueryPlanTrace] ON DATABASE 
ADD EVENT sqlserver.query_post_execution_showplan
ADD TARGET package0.ring_buffer
WITH (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_MULTIPLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=30 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=OFF,STARTUP_STATE=OFF)
GO

ALTER EVENT SESSION [QueryPlanTrace] ON DATABASE STATE = START
GO

SQL Database では、トレースフラグ 7412 が使用できないため、「SET STATISTICS XML ON」「SET STATISTICS PROFILE ON」を有効にするか、上記の拡張イベントを設定することにより、クエリの進行状況を取得することができます。

上記の拡張イベントを開始した後に実行されたクエリに関しては、クエリの進行状況を取得することができるようになりますので、デバッグや問題発生時に使用することができるかと。

SQL Database では、利用状況モニターが使用できないため、以下のようなクエリで進行状況を取得する必要があります。

SELECT
    qp.session_id, 
	DB_NAME(qp.database_id) AS db_name,
    qp.request_id, 
    ot.task_state,
    qp.physical_operator_name, 
    qp.node_id, 
    qp.thread_id, 
    qp.row_count,
    qp.estimate_row_count,
	qp.elapsed_time_ms,
	qp.cpu_time_ms
FROM
    sys.dm_exec_query_profiles qp
    CROSS APPLY
    sys.dm_exec_sql_text (sql_handle) t
    CROSS APPLY
    sys.dm_exec_query_plan(plan_handle) p
    LEFT JOIN
    sys.dm_os_tasks ot
ON
    qp.task_address = ot.task_address
WHERE
	qp.session_id <> @@SPID
ORDER BY
    session_id, request_id, node_id, thread_id

 

実行結果としては以下のような情報が取得できます。

image

 

SQL Database の基本的なトレースとしては、上記の 2 種類が基本的なものになるのかなと。

Written by masayuki.ozawa

1月 21st, 2017 at 11:42 pm

Posted in SQL Database

Tagged with

Leave a Reply

*