最も古いアクティブなクエリの統計情報

最も古いアクティブなクエリ(長時間実行中のクエリとも呼ばれる)は、データベース内でアクティブなクエリのリストであり、クエリの実行時間順に並べられています。これらのクエリを分析して、システムのレイテンシと CPU 使用率が高い場合の原因を特定できます。

Spanner には、実行中クエリ(DML ステートメントを含むクエリなど)を開始時間別に昇順で一覧表示する組み込みテーブル SPANNER_SYS.OLDEST_ACTIVE_QUERIES が用意されています。このテーブルに変更ストリーム クエリは含まれません。

現在大量のクエリが実行中の場合、システムがこのデータの収集に関して適用するメモリの制約により、結果は合計クエリのサブセットに限定される可能性があります。そのため、Spanner には SPANNER_SYS.ACTIVE_QUERIES_SUMMARY という追加のテーブルがあり、すべてのアクティブなクエリ(変更ストリーム クエリは除く)の統計情報の概要が表示されます。SQL ステートメントを使用すると、これらの組み込みテーブルの両方から情報を取得できます。

このドキュメントでは、両方のテーブルについて説明し、これらのテーブルを使用するクエリの例を紹介します。最後に、アクティブなクエリによって発生する問題を軽減するのに役立つテーブルの使用方法を示します。

可用性

SPANNER_SYS データは SQL インターフェースを介してのみ使用できます。例えば:

Spanner が提供する他の単一読み取りメソッドは、SPANNER_SYS をサポートしていません。

OLDEST_ACTIVE_QUERIES

SPANNER_SYS.OLDEST_ACTIVE_QUERIES は、開始時間で並べ替えられたアクティブなクエリのリストを返します。現在大量のクエリが実行中の場合、Spanner がこのデータの収集に関して適用するメモリの制約により、結果は合計クエリのサブセットに限定される可能性があります。アクティブなすべてのクエリの統計情報の概要を表示するには、ACTIVE_QUERIES_SUMMARY をご覧ください。

テーブル スキーマ

列名 説明
START_TIME TIMESTAMP クエリの開始時間。
TEXT_FINGERPRINT INT64 フィンガープリントは、トランザクションに含まれるオペレーションのハッシュです。
TEXT STRING クエリ ステートメントのテキスト。
TEXT_TRUNCATED BOOL TEXT フィールドのクエリテキストが切り捨てられた場合は true、それ以外の場合は false です。
SESSION_ID STRING クエリを実行しているセッションの ID。これはオブザーバビリティに使用されます。
QUERY_ID STRING クエリの ID。この ID を CALL cancel_query(query_id) とともに使用して、クエリをキャンセルします。

クエリの例

次の SQL ステートメントの例は、クライアント ライブラリGoogle Cloud CLI、または Google Cloud コンソールを使用して実行できます。

最も古い実行中クエリを一覧表示する

次のクエリは、クエリの開始時間で並べ替えて、最も古い実行中クエリのリストを返します。

SELECT start_time,
       text_fingerprint,
       text,
       text_truncated,
       session_id
FROM spanner_sys.oldest_active_queries
ORDER BY start_time ASC;
start_time text_fingerprint テキスト text_truncated session_id
2020-07-18T07:52:28.225877Z -3426560921851907385 SELECT a.SingerId, a.AlbumId, a.TrackId, b.SingerId as b_id, b.AlbumId as b_albumid, b.TrackId as b_trackId FROM Songs as a CROSS JOIN Songs as b; False ACjbPvYsucrtcffHrRK6aObeIjZf12tSUwOsim-g1WC3IhqF4epzICCQR3GCHw
2020-07-18T07:54:08.622081Z -9206690983832919848 SELECT a.SingerId, a.AlbumId, a.TrackId, a.SongName, s.FirstName, s.LastName FROM Songs as a JOIN Singers as s ON s.SingerId = a.SingerId WHERE STARTS_WITH(s.FirstName, 'FirstName') LIMIT 1000000; False ACjbPvaF3yKiNfxXFod2LPoFaXjKR759Bw1o34206vv0t7eOrD3wxZhu8U6ohQ
2020-07-18T07:54:08.631744Z -105437553161169030 SELECT a.SingerId, a.AlbumId, a.TrackId, a.SongName, s.FirstName, s.LastName FROM Songs as a JOIN Singers as s ON s.SingerId = a.SingerId WHERE a.SingerId > 7 LIMIT 1000000; False ACjbPvanq3MesDNT98t64KdKAz3TlDZoCC-zgW-FJn91cJHuczQ_cOFN_Hdflw
2020-07-18T07:54:08.720011Z -9206690983832919848 SELECT a.SingerId, a.AlbumId, a.TrackId, a.SongName, s.FirstName, s.LastName FROM Songs as a JOIN Singers as s ON s.SingerId = a.SingerId WHERE STARTS_WITH(s.FirstName, 'FirstName') LIMIT 1000000; False ACjbPvYIE2QHkhnmMXuAGpB4inK7yMnQjmYgQ9FoygKNaB5KCXu7Sf7f9aghYw
2020-07-18T07:54:08.731006Z 6561582859583559006 SELECT a.SingerId, a.AlbumId, a.TrackId, a.SongName, s.FirstName, s.LastName FROM Songs as a JOIN Singers as s ON s.SingerId = a.SingerId WHERE a.SingerId > 10 LIMIT 1000000; False ACjbPvYNZ06N2YyvwV0YMlSRBNDtXBqZEK-iAAyPFnFcTmshPvzWkhr034ud7w

上位 2 つの最も古い実行中クエリの一覧表示

上記のクエリを少しだけ変えると、この例では、クエリの開始時間で並び替えられた上位 2 つの最も古い実行中クエリを返します。

SELECT start_time,
       text_fingerprint,
       text,
       text_truncated,
       session_id
FROM spanner_sys.oldest_active_queries
ORDER BY start_time ASC LIMIT 2;
クエリ出力
start_time text_fingerprint テキスト text_truncated session_id
2020-07-18T07:52:28.225877Z -3426560921851907385 SELECT a.SingerId, a.AlbumId, a.TrackId, b.SingerId as b_id, b.AlbumId as b_albumid, b.TrackId as b_trackId FROM Songs as a CROSS JOIN Songs as b; False ACjbPvYsucrtcffHrRK6aObeIjZf12tSUwOsim-g1WC3IhqF4epzICCQR3GCHw
2020-07-18T07:54:08.622081Z -9206690983832919848 SELECT a.SingerId, a.AlbumId, a.TrackId, a.SongName, s.FirstName, s.LastName FROM Songs as a JOIN Singers as s ON s.SingerId = a.SingerId WHERE STARTS_WITH(s.FirstName, 'FirstName') LIMIT 1000000; False ACjbPvaF3yKiNfxXFod2LPoFaXjKR759Bw1o34206vv0t7eOrD3wxZhu8U6ohQ

ACTIVE_QUERIES_SUMMARY

その名前が示すように、組み込みテーブル、SPANNER_SYS.ACTIVE_QUERIES_SUMMARY には、すべてのアクティブなクエリの統計情報の概要を表示されます。次のスキーマに示すように、クエリは経過時間ごとに 3 つのバケットまたはカウンタ(1 秒間以上、10 秒以上、100 秒以上のもの)に分類されます。

テーブル スキーマ

列名 説明
ACTIVE_COUNT INT64 実行中のクエリの合計数。
OLDEST_START_TIME TIMESTAMP 最も古い実行中クエリの開始時間の上限。
COUNT_OLDER_THAN_1S INT64 1 秒以上経過したクエリの数。
COUNT_OLDER_THAN_10S INT64 10 秒以上経過したクエリの数。
COUNT_OLDER_THAN_100S INT64 100 秒以上経過したクエリの数。

1 つのクエリは、これらのバケットの 1 つ以上でカウントされる場合があります。たとえば、クエリが 12 秒間実行されている場合、両方の条件を満たしているため、COUNT_OLDER_THAN_1SCOUNT_OLDER_THAN_10S でカウントされます。

クエリの例

次の SQL ステートメントの例は、クライアント ライブラリgcloud Spanner、または Google Cloud コンソールを使用して実行できます。

アクティブなクエリの概要を取得する

次のクエリは、実行中のクエリに関する統計情報の概要を返します。

SELECT active_count,
       oldest_start_time,
       count_older_than_1s,
       count_older_than_10s,
       count_older_than_100s
FROM spanner_sys.active_queries_summary;
クエリ出力
active_count oldest_start_time count_older_than_1s count_older_than_10s count_older_than_100s
22 2020-07-18T07:52:28.225877Z 21 21 1

制限事項

ここでの目的は最も包括的な分析を可能にすることにありますが、状況によっては、これらのテーブルに返されるデータにクエリが含まれていない場合があります。

  • DML クエリ(UPDATE/INSERT/DELETE)は、ミューテーションの適用フェーズ中は含まれません。

  • 一時的なエラーが原因で再起動中の場合、クエリは含まれません。

  • 過負荷のサーバーや応答がないサーバーのクエリは含まれません。

  • OLDEST_ACTIVE_QUERIES は読み取り / 書き込みトランザクションでは使用できません。読み取り専用トランザクションでも、トランザクション タイムスタンプを無視して、常に実行時の現在のデータを返します。まれに、部分的な結果で ABORTED エラーが返されることがあります。その場合は、部分的な結果を破棄して、もう一度クエリを実行してください。

アクティブなクエリデータを使用して CPU 使用率が高い場合のトラブルシューティングを行う

クエリ統計トランザクション統計は、Spanner データベースでのレイテンシのトラブルシューティングに役立つ情報を提供します。これらのツールは、完了したクエリに関する情報を提供します。ただし、システムで実行されているクエリの情報が必要になる場合もあります。たとえば、CPU 使用率が非常に高く、次の質問に答えたい場合を考えてみます

  • 現在、実行中のクエリの数は?
  • それらはどのようなクエリですか?
  • 長時間(100 秒以上)実行されているクエリの数はいくつですか?
  • クエリを実行しているセッションはどれですか?

上記の質問の答えに応じて、次の操作を行うことができます。

  • 即時解決のためにクエリを実行しているセッションを削除する。
  • インデックスを追加してクエリのパフォーマンスを向上させる。
  • クエリが定期的なバックグラウンド タスクに関連付けられている場合は、そのクエリの頻度を減らす。
  • クエリを実行する権限を持たないユーザーまたはコンポーネントが発行しているクエリを特定する。

このチュートリアルでは、アクティブなクエリを調べ、行うべき操作(もしあれば)を決定します。

アクティブなクエリの概要を取得する

このシナリオの例では、通常の CPU 使用率を上回っているため、次のクエリを実行してアクティブなクエリの概要を返します。

SELECT active_count,
       oldest_start_time,
       count_older_than_1s,
       count_older_than_10s,
       count_older_than_100s
FROM spanner_sys.active_queries_summary;

クエリは次の結果を生成します。

active_count oldest_start_time count_older_than_1s count_older_than_10s count_older_than_100s
22 2020-07-18T07:52:28.225877Z 21 21 1

100 秒を超える時間実行されているクエリが 1 つあることが判明しました。これはデータベースには珍しいため、さらに詳しく調査する必要があります。

アクティブなクエリのリストを取得する

前のステップで、100 秒以上実行されているクエリがあることが判別されました。さらに詳しく調査するため、次のクエリを実行して、上位 5 件の最も古い実行中クエリに関する詳細情報を返します。

SELECT start_time,
       text_fingerprint,
       text,
       text_truncated,
       session_id,
       query_id
FROM spanner_sys.oldest_active_queries
ORDER BY start_time ASC LIMIT 5;

この例では、2024 年 3 月 28 日のおよそ午後 4 時 44 分 9 秒(EDT)にクエリを実行し、次の結果が返されました(出力全体を確認するには、横方向のスクロールが必要な場合もあります)。

start_time text_fingerprint テキスト text_truncated session_id query_id
2024-03-28 16:44:09.356939+00:00 -2833175298673875968 select * from spanner_sys.oldest_active_queries false ACjbPvYsucrtcffHrRK6aObeIjZf12tSUwOsim-g1WC3IhqF4epzICCQR3GCHw 37190103859320827
2020-07-18T07:52:28.225877Z -3426560921851907385 SELECT a.SingerId, a.AlbumId, a.TrackId, b.SingerId as b_id, b.AlbumId as b_albumid, b.TrackId as b_trackId FROM Songs as a CROSS JOIN Songs as b; false ACjbPvaF3yKiNfxXFod2LPoFaXjKR759Bw1o34206vv0t7eOrD3wxZhu8U6ohQ 48946620525959556

最も古いクエリ(フィンガープリントが -2833175298673875968)がテーブル内でハイライト表示されます。これはコストが高い CROSS JOIN ので、 対処します。

コストの高いクエリをキャンセルする

この例では、コストの高い CROSS JOIN を実行しているクエリが見つかったため、このクエリをキャンセルします。前のステップで取得したクエリ結果には query_id が含まれています。GoogleSQL の場合は次の CALL cancel_query(query_id) コマンドを、PostgreSQL の場合は spanner.cancel_query(query_id) コマンドを実行して、クエリをキャンセルできます。

GoogleSQL

CALL cancel_query(query_id)

PostgreSQL

CALL spanner.cancel_query(query_id)

たとえば、次の CALL ステートメントは、ID 37190103859320827 のクエリをキャンセルします。

CALL cancel_query('37190103859320827')

クエリがキャンセルされたことを確認するには、spanner_sys.oldest_active_queries テーブルに対してクエリを実行する必要があります。

このチュートリアルでは、SPANNER_SYS.OLDEST_ACTIVE_QUERIESSPANNER_SYS.ACTIVE_QUERIES_SUMMARY を使用して、実行中のクエリを分析し、CPU 使用率の上昇の原因となるクエリに対して必要に応じて対処する方法を示します。もちろん、コストのかかるオペレーションを回避し、ユースケースに適したスキーマを設計すると、より低コストになります。効率的に実行される SQL ステートメントの作成方法については、SQL のベスト プラクティスをご覧ください。

次のステップ