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

最も古いアクティブなクエリ(長時間実行中のクエリとも呼ばれる)は、データベース内で現在アクティブなクエリのリストであり、クエリの実行時間順に並べられています。これらのクエリを分析して、システムのレイテンシと 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。セッション 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; 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; 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; 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; 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; 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; 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; 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
FROM spanner_sys.oldest_active_queries
ORDER BY start_time ASC LIMIT 5;

この例では、2020 年 7 月 18 日(土)のおよそ午前 12 時 54 分 18 秒(太平洋夏時間)にクエリを実行した結果、次の結果が生成されました(出力全体を確認するには、横方向のスクロールが必要な場合もあります)。

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; 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; 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; 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; ACjbPvYNZ06N2YyvwV0YMlSRBNDtXBqZEK-iAAyPFnFcTmshPvzWkhr034ud7w

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

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

コストの高い CROSS JOIN を実行しているクエリが見つかったので、このクエリをキャンセルします。前述の手順のクエリ結果には、session_id が含まれています。これは、クエリを実行しているセッションの ID です。この場合、次の gcloud spanner databases sessions delete コマンドを実行して、その ID でセッションを削除することにより、クエリがキャンセルされます。

gcloud spanner databases sessions delete\
   ACjbPvYsucrtcffHrRK6aObeIjZf12tSUwOsim-g1WC3IhqF4epzICCQR3GCHw \
    --database=singer_db --instance=test-instance

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

次のステップ