profiling-transaction-fingerprints について
CockroachDB エンジニア向けに、SQL と過去のトランザクション統計からリトライ、競合、コミット遅延を調べるスキルです。DB Console へのアクセスなしで分析でき、トランザクションを構成するステートメント指紋も追跡できます。
主な機能
- 01過去のリトライとコミット遅延の分析
- 02アプリケーション別のリトライ傾向の特定
- 03トランザクション内のステートメント構成の確認
- 04トランザクションとステートメント指紋の関連付け
- 05ネットワーク、メモリー、ディスク使用量の評価
活用シーン
- 01トランザクションのリトライ集中の調査
- 02コミット遅延が大きいトランザクションの分析
- 03リトライの原因となるステートメントの特定
- 04アプリケーション単位のトランザクション健全性の把握
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ cockroachlabs/ cockroachdb-skills --skill profiling-transaction-fingerprintsインストール後、Claude Code で/profiling-transaction-fingerprintsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/json-field-reference.mdmetrics-and-units.mdsql-query-variations.md詳細
トランザクションフィンガープリントのプロファイリング
集約された SQL 統計を使用して過去のトランザクションパフォーマンスの傾向を分析し、再試行の多いトランザクション、競合パターン、コミットレイテンシの問題を特定します。crdb_internal.transaction_statistics を使用して、再試行の動作、コミットレイテンシ、ステートメント構成を時間枠ごとに分析します。すべて SQL 経由で行うため、DB Console にアクセスする必要はありません。
profiling-statement-fingerprints の補完: このスキルはトランザクションレベルのパターン(再試行を伴うステートメントのグループ)を分析します。ステートメントレベルの最適化については、profiling-statement-fingerprints を参照してください。
triaging-live-sql-activity の補完: このスキルは過去のトランザクションパターンを分析します。現在実行中のトランザクションをすぐにトリアージするには、triaging-live-sql-activity を参照してください。
このスキルを使用する場面
- 再試行回数の多いトランザクションを特定する
- トランザクションフィンガープリントのコミットレイテンシの傾向を分析する
- トランザクション境界での競合が多いトランザクションを見つける
- 問題のあるトランザクションのステートメント構成を把握する
- トランザクションの再試行ストームや中断パターンを調査する
- DB Console にアクセスせず、SQL のみで過去のトランザクションを分析する
インシデントにすぐ対応する場合: triaging-live-sql-activity を使用して、現在実行中のトランザクションをトリアージし、暴走した処理をキャンセルします。 ステートメントレベルの最適化を行う場合: profiling-statement-fingerprints を使用して、個々のクエリパターンを分析します。
前提条件
- CockroachDB クラスターへの SQL 接続
- クラスター全体を可視化するための
VIEWACTIVITYまたはVIEWACTIVITYREDACTEDクラスター権限- profiling-statement-fingerprints と同じ権限要件です
- トランザクションパフォーマンスの概念に関する理解
- トランザクション統計の収集が有効であること(デフォルト):
sql.stats.automatic_collection.enabled = true
トランザクション統計の収集を確認する:
SHOW CLUSTER SETTING sql.stats.automatic_collection.enabled;
-- Should return: true
RBAC の設定については、triaging-live-sql-activity の権限リファレンスを参照してください(権限は同じです)。
主な概念
トランザクションフィンガープリントと実行中のトランザクション
トランザクションフィンガープリント: パラメーター化された定数を含むステートメントをグループ化した、正規化済みのトランザクションパターンです。
主な違い:
- 時間範囲: 過去の時間単位のバケットとリアルタイムの現在の状態
- 粒度: 集約された再試行/コミット統計と、個々のトランザクションインスタンス
- 関係: トランザクションはステートメントフィンガープリントの集合です
時系列のバケット化
aggregated_ts: UTC の時間単位のバケットです(例:2026-02-21 14:00:00 は 14:00~14:59 の実行を示します)
データ保持: 保持期間は時間ではなく行数によって制限されます。sql.stats.persisted_rows.max(デフォルトは 1,000,000)によって永続化されるステートメントとトランザクションの行数が制限されます。上限に達すると、古いバケットが圧縮されます。実際に保持される時間範囲は、ワークロードの多様性によって異なります。
ベストプラクティス: 常に時間範囲で絞り込みます:WHERE aggregated_ts > now() - INTERVAL '24 hours'
集約メトリクスとサンプリングメトリクス
| メトリクスカテゴリ | JSON パス | 対象範囲 | 用途 |
|---|---|---|---|
| 集約 | statistics.statistics.* | すべての実行 | 再試行、コミットレイテンシ、実行回数 |
| サンプリング | statistics.execution_statistics.* | sql.txn_stats.sample_rate(デフォルトは 0.01)で制御される確率的なサンプル | 競合、ネットワーク、メモリ/ディスク |
重要: サンプリングメトリクスには、サンプルサイズを示す cnt フィールドがあります。必ず確認してください:
WHERE (statistics->'execution_statistics'->>'cnt') IS NOT NULL
JSON フィールドの抽出
CockroachDB は、トランザクションのメタデータと統計情報を JSONB として保存します。次の演算子を使用します。
演算子:
->:JSON オブジェクト/値を抽出します(JSON を返します)->>:テキストとして抽出します(テキストを返します)::TYPE:指定した型にキャストしますencode(fingerprint_id, 'hex'):バイナリ形式のフィンガープリントを 16 進文字列に変換します
トランザクション固有の例:
encode(fingerprint_id, 'hex') AS txn_fingerprint_id -- Hex encoding
(statistics->'statistics'->>'maxRetries')::INT -- Max retry count
(statistics->'statistics'->'retryLat'->>'mean')::FLOAT8 -- Retry latency (seconds)
(statistics->'statistics'->'commitLat'->>'mean')::FLOAT8 -- Commit latency (seconds)
(statistics->'statistics'->'svcLat'->>'mean')::FLOAT8 -- Service latency (seconds)
metadata->'stmtFingerprintIDs' AS stmt_fingerprint_ids_json -- Statement composition
単位:
- レイテンシーのフィールド:秒(FLOAT8)
- CPU/競合:ナノ秒(秒にするには 1e9 で割ります)
- メモリ/ディスク:バイト(MB にするには / 1048576 を検討してください)
完全なスキーマについては、JSON フィールドリファレンスを参照してください。
ステートメントの構成
metadata.stmtFingerprintIDs: トランザクションと構成ステートメントを対応付ける JSONB 配列
ユースケース: 再試行の多いトランザクションを構成するステートメントを把握します
相互参照のワークフロー: フィンガープリント ID を使って、transaction_statistics と statement_statistics を結合します
パターン例:
-- Extract statement fingerprint IDs from transaction
metadata -> 'stmtFingerprintIDs' AS stmt_ids
-- Use with jsonb_array_elements_text to expand and join
jsonb_array_elements_text(metadata->'stmtFingerprintIDs') AS stmt_fingerprint_id
主な診断クエリ
クエリ 1:再試行と競合が多いトランザクション
-- Identify transactions with high retry counts and contention
SELECT
encode(fingerprint_id, 'hex') AS txn_fingerprint_id,
metadata->>'db' AS database,
metadata->>'app' AS application,
(statistics->'statistics'->>'cnt')::INT AS execution_count,
(statistics->'statistics'->>'maxRetries')::INT AS max_retries,
(statistics->'statistics'->'retryLat'->>'mean')::FLOAT8 AS mean_retry_lat_seconds,
(statistics->'execution_statistics'->'contentionTime'->>'mean')::FLOAT8 / 1e9 AS mean_contention_seconds,
aggregated_ts
FROM crdb_internal.transaction_statistics
WHERE aggregated_ts > now() - INTERVAL '24 hours'
AND (statistics->'statistics'->>'maxRetries')::INT > 0
ORDER BY (statistics->'statistics'->>'maxRetries')::INT DESC
LIMIT 20;
主なカラム: max_retries は再試行回数の最大値、mean_retry_lat_seconds は再試行に費やした時間、mean_contention_seconds はロック待機時間を示します。
解釈: max_retries が高い値(>10)の場合はトランザクションの競合が発生している可能性があります。競合と相関させて、ロックのホットスポットを特定します。
クエリ 2:ステートメント構成の分析
-- Extract statement fingerprints for high-retry transactions
SELECT
encode(t.fingerprint_id, 'hex') AS txn_fingerprint_id,
t.metadata->>'app' AS application,
(t.statistics->'statistics'->>'maxRetries')::INT AS max_retries,
jsonb_array_length(t.metadata->'stmtFingerprintIDs') AS num_statements,
t.metadata->'stmtFingerprintIDs' AS stmt_fingerprint_ids,
t.aggregated_ts
FROM crdb_internal.transaction_statistics t
WHERE t.aggregated_ts > now() - INTERVAL '24 hours'
AND (t.statistics->'statistics'->>'maxRetries')::INT > 10
AND t.metadata->'stmtFingerprintIDs' IS NOT NULL
ORDER BY max_retries DESC
LIMIT 20;
主なカラム: num_statements はトランザクションの複雑さを示し、stmt_fingerprint_ids には statement_statistics との相互参照に使うステートメント ID が含まれます。
ユースケース: どのステートメントの組み合わせが再試行を引き起こすかを把握します。クエリ 7 を使って、具体的なステートメントを詳しく調べます。
クエリ 3:コミットレイテンシーが高いトランザクション
-- Find transactions with slow commit latency
SELECT
encode(fingerprint_id, 'hex') AS txn_fingerprint_id,
metadata->>'db' AS database,
metadata->>'app' AS application,
(statistics->'statistics'->>'cnt')::INT AS execution_count,
(statistics->'statistics'->'commitLat'->>'mean')::FLOAT8 AS mean_commit_lat_seconds,
(statistics->'statistics'->'svcLat'->>'mean')::FLOAT8 AS mean_service_lat_seconds,
ROUND(
((statistics->'statistics'->'commitLat'->>'mean')::FLOAT8 /
NULLIF((statistics->'statistics'->'svcLat'->>'mean')::FLOAT8, 0)) * 100, 2
) AS commit_pct_of_service_lat,
aggregated_ts
FROM crdb_internal.transaction_statistics
WHERE aggregated_ts > now() - INTERVAL '24 hours'
AND (statistics->'statistics'->'commitLat'->>'mean')::FLOAT8 > 0.1 -- > 100ms commit latency
ORDER BY (statistics->'statistics'->'commitLat'->>'mean')::FLOAT8 DESC
LIMIT 20;
主なカラム: mean_commit_lat_seconds は 2PC のコミット時間、commit_pct_of_service_lat は全体のレイテンシーに占めるコミットのオーバーヘッドの割合を示します。
解釈: コミットの割合が高い(>20%)場合は、分散トランザクションのオーバーヘッド、レプリケーションの遅延、またはリージョン間の書き込みが原因の可能性があります。
クエリ 4:アプリケーション別の再試行率
-- Analyze retry patterns by application
SELECT
metadata->>'app' AS application,
metadata->>'db' AS database,
COUNT(*) AS transaction_fingerprint_count,
SUM((statistics->'statistics'->>'cnt')::INT) AS total_executions,
AVG((statistics->'statistics'->>'maxRetries')::INT) AS avg_max_retries,
MAX((statistics->'statistics'->>'maxRetries')::INT) AS overall_max_retries,
AVG((statistics->'statistics'->'retryLat'->>'mean')::FLOAT8) AS avg_retry_lat_seconds
FROM crdb_internal.transaction_statistics
WHERE aggregated_ts > now() - INTERVAL '24 hours'
AND (statistics->'statistics'->>'maxRetries')::INT > 0
GROUP BY metadata->>'app', metadata->>'db'
ORDER BY avg_max_retries DESC
LIMIT 20;
ユースケース: アプリケーションレベルの健全性スコアカードとして使用し、問題のあるトランザクションパターンが最も多いアプリケーションを特定します。
カスタマイズ: 傾向を把握するには時間範囲を 7 日に変更し、特定のデータベースでフィルターします。
クエリ 5:トランザクションのリソース消費量
-- Find transactions with high resource usage
SELECT
encode(fingerprint_id, 'hex') AS txn_fingerprint_id,
metadata->>'app' AS application,
(statistics->'statistics'->>'cnt')::INT AS execution_count,
(statistics->'execution_statistics'->'networkBytes'->>'mean')::FLOAT8 / 1048576 AS mean_network_mb,
(statistics->'execution_statistics'->'maxMemUsage'->>'mean')::FLOAT8 / 1048576 AS mean_mem_mb,
(statistics->'execution_statistics'->'maxDiskUsage'->>'mean')::FLOAT8 / 1048576 AS mean_disk_mb,
ROUND(
((statistics->'execution_statistics'->'networkBytes'->>'mean')::FLOAT8 / 1048576) *
(statistics->'statistics'->>'cnt')::INT, 2
) AS estimated_total_network_mb,
aggregated_ts
FROM crdb_internal.transaction_statistics
WHERE aggregated_ts > now() - INTERVAL '24 hours'
AND (statistics->'execution_statistics'->>'cnt') IS NOT NULL
AND (statistics->'execution_statistics'->'networkBytes'->>'mean')::FLOAT8 > 0
ORDER BY estimated_total_network_mb DESC
LIMIT 20;
主なカラム: mean_network_mb は分散トランザクションのオーバーヘッドを示します。mean_disk_mb が 0 を超える場合は、メモリからディスクへのスピルが発生しています。
解釈: ネットワークバイト数が多い場合は、リージョン間トランザクションまたは非効率な分散が考えられます。ディスク使用量はメモリ不足を示します。
クエリ 6:再試行レイテンシーの内訳
-- Understand retry latency as percentage of service latency
SELECT
encode(fingerprint_id, 'hex') AS txn_fingerprint_id,
metadata->>'app' AS application,
(statistics->'statistics'->>'cnt')::INT AS execution_count,
(statistics->'statistics'->>'maxRetries')::INT AS max_retries,
(statistics->'statistics'->'retryLat'->>'mean')::FLOAT8 AS mean_retry_lat_seconds,
(statistics->'statistics'->'svcLat'->>'mean')::FLOAT8 AS mean_service_lat_seconds,
ROUND(
((statistics->'statistics'->'retryLat'->>'mean')::FLOAT8 /
NULLIF((statistics->'statistics'->'svcLat'->>'mean')::FLOAT8, 0)) * 100, 2
) AS retry_pct_of_service_lat,
aggregated_ts
FROM crdb_internal.transaction_statistics
WHERE aggregated_ts > now() - INTERVAL '24 hours'
AND (statistics->'statistics'->>'maxRetries')::INT > 0
AND (statistics->'statistics'->'retryLat'->>'mean')::FLOAT8 > 0
ORDER BY retry_pct_of_service_lat DESC
LIMIT 20;
解釈: 再試行の割合が高い(>30%)場合、レイテンシーの大半が競合による再試行に費やされています。トランザクションの境界またはスキーマを最適化してください。
クエリ 7:トランザクションとステートメントの相互参照
-- Join transaction statistics with statement statistics to see constituent statements
SELECT
encode(t.fingerprint_id, 'hex') AS txn_fingerprint_id,
t.metadata->>'app' AS txn_application,
(t.statistics->'statistics'->>'maxRetries')::INT AS txn_max_retries,
stmt_fp_id AS stmt_fingerprint_id,
s.metadata->>'query' AS statement_query,
(s.statistics->'statistics'->'runLat'->>'mean')::FLOAT8 AS stmt_mean_run_lat_seconds,
t.aggregated_ts
FROM crdb_internal.transaction_statistics t
CROSS JOIN LATERAL jsonb_array_elements_text(t.metadata->'stmtFingerprintIDs') AS stmt_fp_id
LEFT JOIN crdb_internal.statement_statistics s
ON s.fingerprint_id = decode(stmt_fp_id, 'hex')
AND s.aggregated_ts = t.aggregated_ts
WHERE t.aggregated_ts > now() - INTERVAL '24 hours'
AND (t.statistics->'statistics'->>'maxRetries')::INT > 10
AND t.metadata->'stmtFingerprintIDs' IS NOT NULL
ORDER BY txn_max_retries DESC, stmt_mean_run_lat_seconds DESC
LIMIT 50;
ユースケース: 再試行の多いトランザクションから、問題のある具体的なステートメントを詳しく調べます。トランザクション内のどのステートメントが再試行を引き起こしているかを特定します。
注: decode(stmt_fp_id, 'hex') を使って 16 進文字列をバイナリに戻し、statement_statistics と結合します。
よくあるワークフロー
ワークフロー 1:再試行ストームの調査
- 再試行の多いトランザクションを特定します: クエリ 1 を実行し、
max_retries > 20に注目します - アプリケーション別に再試行パターンを分析します: クエリ 4 を実行し、問題のあるアプリを特定します
- ステートメントの構成を調べます: クエリ 7 を実行し、再試行の多いトランザクションにどのステートメントが含まれているかを確認します
- 実行中のアクティビティと相互参照します: 問題が継続中の場合は、triaging-live-sql-activity を使って現在のトランザクション状態を確認します
- 是正します: トランザクションの境界を調整し、操作をバッチ化し、手順 3 で特定したステートメントを最適化します
ワークフロー 2:コミット遅延の分析
- 遅いコミットトランザクションを特定します: Query 3 を実行し、
commit_pct_of_service_lat > 20%に注目します - 競合との相関を確認します: 同じトランザクションフィンガープリントについて Query 1 を実行し、競合との関連を確認します
- 時間パターンを分析します: Query 3 を
aggregated_tsでグループ化し、ピーク期間を特定します - リソースを調査します: Query 5 を実行し、ネットワークオーバーヘッドとコミット遅延に相関があるか確認します
- 修正します: 操作のバッチ処理、テーブルのパーティショニング、レプリケーション設定の調査を検討します
ワークフロー 3:ステートメント構成の詳細分析
- 問題のあるトランザクションを特定します: Query 1 または Query 3 を実行し、再試行回数が多い、またはコミットが遅いトランザクションを見つけます
- ステートメント ID を抽出します: Query 2 を実行し、対象のトランザクションの
stmtFingerprintIDsを確認します - statement_statistics と結合します: Query 7 を実行し、ステートメントの詳細を確認します
- ボトルネックとなるステートメントを最適化します: profiling-statement-fingerprints スキルを使って、特定したステートメントを分析、最適化します
- 再試行の減少を検証します: 最適化後に Query 1 を再実行し、再試行回数が改善したことを確認します
ワークフロー 4:アプリケーションのヘルススコアカード
- アプリごとの再試行メトリクスを生成します: Query 4 を実行し、アプリケーションレベルの再試行統計を取得します
- コミット遅延との相関を確認します: Query 3 を変更して、アプリケーションごとにグループ化します
- リソースの帰属を確認します: Query 5 をアプリケーションごとにグループ化して実行し、リソースへの影響を確認します
- 傾向を分析します: 7 日間のウィンドウでクエリを実行し、1 時間ごとのバケットを比較します
- アプリケーションチームに連絡します: 調査用に、再試行回数またはレイテンシーが高い具体的なトランザクションフィンガープリントを提示します
安全上の考慮事項
読み取り専用の操作:
すべてのクエリは、crdb_internal.transaction_statistics に対する SELECT 文です。本番環境での使用が承認されており、診断に安全です。
パフォーマンスへの影響:
| 考慮事項 | 影響 | 緩和策 |
|---|---|---|
| 大きなテーブル | トランザクションの種類が多いほど、行数が増えます | 必ず WHERE aggregated_ts > now() - INTERVAL '24 hours' と LIMIT を指定します |
| JSON の解析 | JSONB 抽出による CPU オーバーヘッド | タイトなループを避け、具体的な時間ウィンドウを指定します |
| 広い時間ウィンドウ | 7 日間のクエリでは行数が増えます | 既定では 24 時間とし、必要な場合のみ広げます |
| サンプリングされたメトリクス | NULL 処理のオーバーヘッド | 防御的に WHERE (statistics->'execution_statistics'->>'cnt') IS NOT NULL を使用します |
プライバシー: マルチテナント環境では、VIEWACTIVITYREDACTED を使用してクエリ定数を秘匿します(ステートメントプロファイリングと同様です)。
既定の時間ウィンドウ: 24 時間に設定すると、直近のデータを確認しながら、結果セットを管理しやすい規模に抑えられます。
トラブルシューティング
| 問題 | 原因 | 解決方法 |
|---|---|---|
| 結果が空 | ウィンドウ内にデータがない、または統計情報の収集が無効になっている | sql.stats.automatic_collection.enabled = true を確認します |
column does not exist | JSON フィールドの誤記、またはバージョンの不一致 | フィールド名を確認し、CockroachDB のバージョンを確認します |
| サンプリングされたメトリクスが NULL | バケット内でメトリクスがサンプリングされていない | WHERE (statistics->'execution_statistics'->>'cnt') IS NOT NULL でフィルターします |
fingerprint_id が 16 進数ではない | 既定のバイナリ形式 | 読みやすくするには encode(fingerprint_id, 'hex') を使用します |
| ステートメントの結合に失敗する | aggregated_ts またはフィンガープリント形式が一致していない | 同じ時間バケットを使用し、decode() で適切に型変換されていることを確認します |
| クエリが非常に遅い | 大きなテーブルに時間フィルターがない | 必ず時間ウィンドウと LIMIT を追加します |
stmtFingerprintIDs が空 | 単一ステートメントのトランザクション、または古いバージョン | 単純なトランザクションでは正常です |
主な考慮事項
- 時間範囲: デフォルトは24時間です。傾向を把握するには7日間に広げてください
- サンプリングされたメトリクス: すべての実行が記録されるわけではありません。サンプルサイズ(
cnt)を確認してください - JSON フィールドの安全性: 防御的な NULL チェックを行い、型変換エラーに対処してください
- プライバシー: 本番環境ではVIEWACTIVITYREDACTEDを使用してください
- パフォーマンス: 必ず時間フィルターとLIMIT句を含めてください
- ステートメントプロファイリングとの併用: 全体を網羅するには併用してください(トランザクション+ステートメント)
- ライブトリアージとの併用: 履歴上のパターンとリアルタイムの状況を把握するには、両方を使用してください
- データ保持: TTLではなく、行数上限
sql.stats.persisted_rows.max(デフォルトは1,000,000)によって制限されます。有効な時間範囲はワークロードの多様性によって変わります - 再試行の意味:
maxRetriesはバケット内の全実行における最大値であり、平均値ではありません - フィンガープリントのエンコード: 人間が読みやすいIDには
encode(fingerprint_id, 'hex')を使用してください
参考資料
スキルの参考資料:
- JSONフィールドのスキーマと抽出
- メトリクスのカタログと単位
- SQLクエリのバリエーション
- RBACと権限(triaging-live-sql-activityと共通)
CockroachDB公式ドキュメント:
関連スキル:
- profiling-statement-fingerprints - ステートメントレベルの最適化向け
- triaging-live-sql-activity - アクティブなトランザクションの即時トリアージ向け