RDS for SQL Serverで拡張イベントを使ってスロークエリを収集してみた
はじめに
DB のパフォーマンスを監視するために、スロークエリを収集したいという要望は多いと思います。
RDS の監視サービスと言えば CloudWatch Database Insights です。
統合されたダッシュボードで様々なインサイトを得ることができ、スロークエリをモニタリングすることも可能です。
しかし、2025年8月現在、RDS for SQL Server ではスロークエリを閲覧できません。
Slow queries is currently available only for MySQL, PostgreSQL and MariaDB instances.
「スロークエリは現在、MySQL、PostgreSQL、およびMariaDBのインスタンスでのみ利用可能です。」
そこで今回は、SQL Server 標準の拡張イベントを利用して、スロークエリを収集してみました。
拡張イベントとは
拡張イベント (XEvents) は、SQL Server に組み込まれた「軽量でスケーラブルな監視・トラブルシューティング基盤」で、必要なイベントデータを柔軟に収集できます。
注意点として、RDS では以下のような制約があります。
- ターゲット制約
- ファイルターゲットの保存先は
D:\rdsdbdata\log
に固定。任意のドライブやフォルダへの出力はできない。 - ETW (Event Tracing for Windows) ターゲットは利用不可。オンプレのように Windows の ETW インフラへ送ることはできない。
- ファイルターゲットの保存先は
- リソースパラメータの上限を AWS 側で制御
xe_session_max_memory
,xe_session_max_event_size
,xe_session_max_dispatch_latency
,xe_file_target_size
,xe_file_retention
などに AWS 固有の上限値があり、rdsadmin.dbo.rds_set_configuration
経由でしか変更できない。
- Multi-AZ の挙動
- XE セッションはスタンバイインスタンスに自動で引き継がない。
- フェイルオーバー後、新しいプライマリではセッションを再起動する必要がある。
- 継続利用するには、ユーザ側で SQL Server Agent ジョブ等で再起動処理を仕込む必要がある。
- 管理系の制限
- 既存の「既定セッション」は変更できない(オンプレなら ALTER 可能だが、RDS では禁止)。
- メモリパーティションの設定は
NONE
のみサポート。
詳しくは以下の公式ドキュメントも参照してください。
制約はあるものの、スロークエリの収集という用途においては問題なく利用できそうです。
実際にやってみた
今回は 10 秒以上かかるクエリを収集するようにしてみましょう。
拡張イベントセッションの作成
まず、イベントセッションを作成し、セッションを開始します。
-- セッション作成
CREATE EVENT SESSION XE_SlowQuery ON SERVER
ADD EVENT sqlserver.sql_statement_completed(
ACTION (sqlserver.sql_text, sqlserver.database_name, sqlserver.session_id)
WHERE (duration > 10000000)
)
ADD TARGET package0.event_file(
SET filename = N'D:\rdsdbdata\log\XE_SlowQuery',
max_file_size = (100),
max_rollover_files = (5)
)
WITH (MAX_MEMORY=4 MB, EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,
MAX_DISPATCH_LATENCY=30 SECONDS, TRACK_CAUSALITY=OFF, STARTUP_STATE=OFF);
GO
-- セッション開始
ALTER EVENT SESSION XE_SlowQuery ON SERVER STATE = START;
GO
duration
はマイクロ秒単位なので、10 秒以上かかるクエリを収集する場合は、10000000
を指定します。
保存先は RDS 指定のログディレクトリ D:\rdsdbdata\log
で、ファイル名は XE_SlowQuery
としています。
max_file_size
はファイルサイズの上限を指定します。デフォルトは 100MB です。変更する場合は rds_set_configuration
で上限を拡張します(最大 1GB まで拡張可能)
なお、ストアドプロシージャやバッチ処理も収集対象にしたい場合もあると思います。
その際は sqlserver.sql_statement_completed
に加えて sqlserver.rpc_completed
と sqlserver.sql_batch_completed
を追加できます。
スロークエリを発生させる
今回は検証用に、15 秒間の WAIT を入れてスロークエリを発生させます。
WAITFOR DELAY '00:00:15';
結果を確認する
.xel
ファイルの中身を sys.fn_xe_file_target_read_file
で読み出してみます。
WITH xe AS (
SELECT CAST(event_data AS XML) AS x
FROM sys.fn_xe_file_target_read_file('D:\rdsdbdata\log\XE_SlowQuery*.xel', NULL, NULL, NULL)
)
SELECT
x.value('(event/@name)[1]', 'sysname') AS event_name,
x.value('(event/@timestamp)[1]', 'datetime2') AS [timestamp_utc],
x.value('(event/data[@name="duration"]/value)[1]', 'bigint')/1000000.0 AS duration_sec,
x.value('(event/data[@name="cpu_time"]/value)[1]', 'bigint')/1000000.0 AS cpu_sec,
x.value('(event/data[@name="logical_reads"]/value)[1]', 'bigint') AS logical_reads,
x.value('(event/data[@name="writes"]/value)[1]', 'bigint') AS writes,
x.value('(event/data[@name="row_count"]/value)[1]', 'bigint') AS row_count,
x.value('(event/action[@name="database_name"]/value)[1]', 'sysname') AS database_name,
x.value('(event/action[@name="session_id"]/value)[1]', 'int') AS session_id,
x.value('(event/action[@name="sql_text"]/value)[1]', 'nvarchar(max)') AS sql_text
FROM xe
ORDER BY [timestamp_utc] DESC;
以下のような結果が得られました。
良い感じですね。
まとめ
一部制約はあるものの、RDS でも拡張イベントを利用してスロークエリを収集することができました。
また、Database Insights との使い分けという観点では、以下のような分類になるかと思います。
- 重い SQL をざっくり見る -> Database Insights
- 閾値を超えたクエリをログとして残す -> 拡張イベント
普段は Database Insights で監視しつつ、レポートなどで履歴を残す用途では拡張イベントを利用するという使い分けが良さそうです。
まずは開発環境で試してみて、本番環境でも利用できるかを確認してみてください。