クエリプロファイルを使用したクエリの分析

Snowflakeウェブインターフェイスから利用可能なクエリプロファイルは、クエリの実行の詳細を提供します。選択されたクエリについて、クエリの処理計画の主要コンポーネントのグラフィカルな表現、各コンポーネントの統計、およびクエリ全体の詳細と統計が提供されます。

このトピックの内容:

概要

クエリプロファイルを使用する場合

クエリプロファイルは、クエリのメカニズムを理解するための強力なツールです。特定のクエリのパフォーマンスや動作について詳しく知りたい場合や必要な場合に使用できます。 SQL クエリ式の典型的な間違いを見つけて、潜在的なパフォーマンスのボトルネックと改善の機会を特定できるように設計されています。

個々のクエリに関する追加の高レベルの情報は、 Worksheets Worksheet tab ページと History History tab ページのさまざまな列で表示できます。

クエリプロファイルにアクセスする方法

クエリプロファイルには、クエリの詳細ページからアクセスします。そのため、 Query ID 列が表示され、クエリ IDs をクリックできる任意のページからクエリプロファイルにアクセスできます。具体的には:

  • Worksheets Worksheet tab

  • History History tab

注釈

これらのページに Query ID 列が表示されない場合は、ページにある列ヘッダーの1つの横にあるドロップダウンをクリックし、 Columns のリストで Query ID を選択します。

クエリのプロファイルにアクセスするには、

  1. History History tab または Worksheets Worksheet tab ページで、クエリ IDをクリックします。

  2. クエリの詳細ページが表示されます:

    ../_images/ui-profile-detail.png
  3. Profile タブをクリックします。

  4. クエリにプロファイルがある場合は、表示されます(下のスクリーンショットを参照)。

クエリプロファイルインターフェイス

このトピックの目的のために、2つのテーブルを結合する基本的なサンプル SQL クエリを使用しています:

select sum(j)
from x join y using (i)
where j > 300
and i < (select avg(j) from x);

次のスクリーンショットは、このクエリのプロファイルを示しています:

../_images/ui-profile-step1.png

インターフェイスは、次の主要な要素で構成されています:

ステップ

クエリが複数のステップで処理された場合、各ステップを切り替えることができます。

演算子ツリー

中央のペインには、各演算子ノード間の関係を含む、選択したステップのすべての演算子ノードのグラフィック表示が表示されます。

ノードリスト

中央のペインには、実行時間ごとの折りたたみ可能なオペレーターノードのリストが含まれています。

概要

右側のペインには、クエリプロファイルの概要が表示されます。演算子ノードが選択されると、表示は演算子の詳細に変わります。

ステップ

多くの場合、クエリは複数のステップで処理されます。例えば、サンプルクエリは2ステップで処理されました:

  • ステップ1は列 x.j の平均を計算しました。

  • ステップ2はこの中間結果を使用して、最終的なクエリ結果を計算しました。

クエリプロファイルでは、各処理ステップが個別のパネルに表示されます。それぞれのステップをクリックして、パネルを切り替えることができます。サンプルクエリでは、 Step 2 をクリックするとビューが次のように変更されます:

../_images/ui-profile-step2.png

演算子ツリー

このツリーは、クエリを構成する演算子ノードと各演算子を接続するリンクのグラフィカルな表現を提供します:

  • 演算子は、クエリの機能的な構成要素です。データアクセス、変換、更新など、データ管理と処理のさまざまな側面を担当します。ツリーの各演算子ノードには、いくつかの基本的な属性が含まれています。

    <型> [#]

    演算子型と ID 番号。ID はクエリプロファイル内の演算子を一意に識別するために使用できます(例えば、上のスクリーンショットの Aggregate [5] および Join [11] など)。

    すべてのタイプの説明については、以下の 演算子タイプ をご覧ください。

    割合

    クエリステップ内でこの演算子が消費した時間の割合(例えば、 Aggregate [5]25%)。この情報は、演算子ノードの下部にあるオレンジ色のバーにも反映され、パフォーマンスが重要な演算子を簡単に視覚的に識別できます。

    ラベル

    オペレーター固有の追加情報(例えば、 Aggregate [5]SUM(X.J))。

  • リンクは、各演算子ノード間を流れるデータを表します。各リンクは、処理されたレコードの数を提供します(例: Join [11] から Aggregate [5] までの 41.95M)。

注釈

演算子ツリーが表示されない場合、タッチスクリーンのタッチイベントインターフェイスが干渉している可能性があります。インターフェイスを一時的に無効にする手順については、Snowflake Lodgeの こちらの記事 をご覧ください。

実行時間別の演算子ノード

演算子ツリーペインの折りたたみ可能なパネルには、実行時間の降順でノードが一覧表示され、ユーザーは実行時間の観点から最もコストの高い演算子ノードをすばやく見つけることができます。パネルには、クエリの合計実行時間(またはクエリが複数の処理ステップで実行された場合は、表示されたクエリステップの実行時間)の1%以上持続したすべてのノードが一覧表示されます。

リスト内のノードをクリックすると、選択したノードの演算子ツリーが中央に配置されます。

次のスクリーンショットは、 Aggregate [5] 演算子をクリックした後のパネルを示しています:

../_images/ui-profile-nodes-by-execution-time.png

プロファイルの概要/演算子の詳細

右側の概要/詳細ペインには、左側のツリーで選択したコンポーネント(演算子およびリンク)に関する情報が表示されます。表示される情報は、演算子ツリー内のノードが選択されているかどうかによって異なります:

  • 最初は、ツリー内のノードは選択されていないため、パネルには現在のステップの概要情報が表示されます。

  • ノードをクリックしてコンポーネントを選択すると、パネルにコンポーネントの情報が表示されます。

注釈

ノードをクリックした後、ステップレベルの概要情報に戻るには、演算子ツリーの周囲の空のスペースをクリックしてノードの選択を解除するだけです。

概要/詳細ペインは3セクションに分かれています:

実行時間

どの処理タスクがクエリ時間を消費したかについての情報を提供します(以下の クエリ/演算子の詳細 で説明)。さらに、ステップレベルの情報については、指定されたステップの状態とその実行時間を示します。

統計

さまざまな統計に関する詳細情報を提供します(以下の クエリ/演算子の詳細 で説明)。

属性

コンポーネント固有の情報を提供します(以下の 演算子のタイプ で説明)。

次のスクリーンショットは、 Join [11] 演算子をクリックした後の詳細を示しています:

../_images/ui-profile-operator.png

演算子のタイプ

次のセクションでは、最も一般的な演算子タイプとその属性のリストを提供します。

データアクセスおよび生成演算子

TableScan

単一のテーブルへのアクセスを表します。属性:

  • フルテーブル名 ---データベースとスキーマを含む、アクセスされたテーブルの名前。

  • ---スキャンされた列のリスト

  • テーブルエイリアス ---存在する場合は、テーブルエイリアスを使用

  • 抽出されたバリアントパス --- VARIANT 列から抽出されたパスのリスト

ValuesClause

VALUES 句で提供される値のリスト。属性:

  • 値の数 ---生成された値の数。

  • ---生成された値のリスト。

ジェネレーター

TABLE(GENERATOR(...)) 構造を使用してレコードを生成します。属性:

  • rowCount ---指定されたrowCountパラメーター。

  • timeLimit ---指定されたtimeLimitパラメーター。

ExternalScan

ステージオブジェクトに格納されているデータへのアクセスを表します。ステージから直接データをスキャンするクエリの一部になりますが、データロード COPY クエリにも使用できます。属性:

  • ステージ名 ---データが読み取られるステージの名前。

  • ステージタイプ ---ステージのタイプ(例: TABLE STAGE)。

InternalObject

内部データオブジェクト(例えば、情報スキーマテーブルや以前のクエリの結果など)へのアクセスを表します。属性:

  • オブジェクト名 ---アクセスしたオブジェクトの名前またはタイプ。

データ処理演算子

フィルター

レコードをフィルタリングする操作を表します。属性:

  • フィルター条件 -フィルターの実行に使用される条件。

参加する

特定の条件で2つの入力を結合します。属性:

  • 参加タイプ ---参加のタイプ(例: INNER、 LEFT OUTER)

  • 等価結合条件 ---等価ベースの条件を使用する結合の場合、要素の結合に使用される式がリストされます。

  • 追加の結合条件 ---一部の結合では、不平等ベースの述語を含む条件が使用されます。それらはここにリストされています。

注釈

等しくない結合述部は、処理速度を大幅に低下させる可能性があるため、可能であれば回避する必要があります。

集計

入力をグループ化し、集計関数を計算します。 GROUP BYや SELECT DISTINCTなどの SQL 構造を表すことができます。属性:

  • グループ化キー --- GROUP BY が使用される場合、これはグループ化する式をリストします。

  • 集計関数 ---各集計グループに対して計算された関数のリスト(例えば、SUM)。

GroupingSets

GROUPING SETS、 ROLLUP 、 CUBEなどの構造を表します。属性:

  • グループ化キーセット ---グループ化セットのリスト

  • 集計関数 ---各グループに対して計算された関数のリスト(例えば、 SUM)。

WindowFunction

ウィンドウ関数を計算します。属性:

  • ウィンドウ関数 ---計算されたウィンドウ関数のリスト。

ソート

特定の式の入力を順序付けます。属性:

  • キーのソート ---ソート順を定義する式。

SortWithLimit

ソート後に入力シーケンスの一部、通常は SQL の ORDER BY ... LIMIT ... OFFSET ... 構築の結果を生成します。属性:

  • キーのソート ---ソート順を定義する式。

  • 行数 ---生成された行数。

  • オフセット ---生成されたタプルが発行される順序付けられたシーケンス内の位置。

フラット化

VARIANT レコードを処理し、場合によっては指定されたパスでそれらをフラット化します。属性:

  • 入力 ---データをフラット化するために使用される入力式。

JoinFilter

クエリプランでさらに結合の条件に一致しない可能性があると識別できるタプルを削除する特別なフィルタリング操作。属性:

  • 元の結合 ID ---除外できるタプルを識別するために使用される結合。

UnionAll

2つの入力を連結します。属性:なし。

ExternalFunction

外部関数による処理を表します。

DML 演算子

挿入

INSERT または COPY 操作のいずれかにより、テーブルにレコードを追加します。属性:

  • 入力式 ---挿入される式。

  • テーブル名 ---レコードが追加されるテーブルの名前。

削除

テーブルからレコードを削除します。属性:

  • テーブル名 ---レコードが削除されるテーブルの名前。

更新

テーブル内のレコードを更新します。属性:

  • テーブル名 ---更新されたテーブルの名前。

マージ

テーブルで MERGE 操作を実行します。属性:

  • フルテーブル名 ---更新されたテーブルの名前。

アンロード

ステージ内のテーブルからファイルにデータをエクスポートする COPY 操作を表します。属性:

  • 場所 -データが保存されるステージの名前。

メタデータ演算子

一部のクエリには、データ処理操作ではなく、純粋なメタデータ/カタログ操作であるステップが含まれます。これらのステップは、単一の演算子で構成されています。例は次のとおりです:

DDL およびトランザクションコマンド

オブジェクト、セッション、トランザクションなどの作成または変更に使用されます。通常、これらのクエリは仮想ウェアハウスによって処理されず、一致する SQL ステートメントに対応するシングルステッププロファイルになります。例:

CREATE DATABASE | SCHEMA | ...

ALTER DATABASE | SCHEMA | TABLE | SESSION | ...

DROP DATABASE | SCHEMA | TABLE | ...

COMMIT

テーブル作成コマンド

テーブルを作成するためのDDL コマンド。例:

CREATE TABLE

他の DDL コマンドと同様に、これらのクエリはシングルステッププロファイルになります。ただし、 CTAS ステートメントで使用する場合など、マルチステッププロファイルの一部にすることもできます。例:

CREATE TABLE ... AS SELECT ...

クエリ結果の再利用

前のクエリの結果を再利用するクエリ。

メタデータベースの結果

データにアクセスすることなく、メタデータのみに基づいて結果が計算されるクエリ。これらのクエリは、仮想ウェアハウスでは処理されません。例:

SELECT COUNT(*) FROM ...

SELECT CURRENT_DATABASE()

その他の演算子

結果

クエリ結果を返します。属性:

  • 式のリスト -生成された式。

クエリ/演算子の詳細

クエリパフォーマンスの分析に役立つように、詳細パネルには2つのクラスのプロファイリング情報があります:

  • カテゴリに分類された実行時間

  • 詳細な統計

さらに、各演算子に対して属性が提供されます(このトピックの 演算子の種類 で説明)。

実行時間

実行時間は、クエリの処理中に「時間が費やされた場所」に関する情報を提供します。費やした時間は、次の順序で表示される次のカテゴリに分類できます:

  • Processing --- CPUによるデータ処理に費やされた時間。

  • Local Disk IO ---ローカルディスクアクセスによって処理がブロックされた時間。

  • Remote Disk IO ---処理がリモートディスクアクセスによってブロックされた時間。

  • Network Communication ---処理がネットワークデータ転送を待機していた時間。

  • Synchronization ---参加しているプロセス間のさまざまな同期アクティビティ。

  • Initialization ---クエリ処理の設定にかかった時間。

統計

詳細パネルで提供される主な情報源は、次のセクションにグループ化されたさまざまな統計です:

  • IO ---クエリ中に実行される入出力操作に関する情報:

    • スキャンの進行状況 ---これまでに特定のテーブルについてスキャンされたデータの割合。

    • スキャンされたバイト ---これまでにスキャンされたバイト数。

    • キャッシュからスキャンされた割合 ---ローカルディスクキャッシュからスキャンされたデータの割合。

    • 書き込まれたバイト数 ---書き込まれたバイト数(例えば、テーブルへのロード時)。

    • 結果に書き込まれるバイト数 ---結果オブジェクトに書き込まれるバイト数。

    • 結果から読み取ったバイト数 ---結果オブジェクトから読み取ったバイト数。

    • スキャンされた外部バイト数 ---ステージなどの外部オブジェクトから読み取ったバイト数。

  • DML ---データ操作言語(DML)クエリの統計:

    • 挿入された行の数 ---1つまたは複数のテーブルに挿入された行の数。

    • 更新された行の数 ---テーブルで更新された行の数。

    • 削除された行の数 ---テーブルから削除された行の数。

    • アンロードされた行の数 ---データのエクスポート中にアンロードされた行の数。

    • 削除されたバイト数 ---テーブルから削除されたバイト数。

  • Pruning ---テーブルのプルーニングの影響に関する情報:

    • スキャンされたパーティション ---これまでにスキャンされたパーティションの数。

    • パーティションの合計数 ---特定のテーブル内のパーティションの総数。

  • Spilling ---中間結果がメモリに収まらない操作のディスク使用量に関する情報:

    • ローカルストレージに流出したバイト数 ---ローカルディスクに流出したデータの量。

    • リモートストレージに流出したバイト数 ---リモートディスクに流出したデータの量。

  • Network ---ネットワーク通信:

    • ネットワーク経由で送信されたバイト数 --- ネットワーク経由で送信されたデータの量。

  • External Functions --- 外部関数の呼び出しに関する情報。

    次の統計は、 SQL ステートメントによって呼び出される各外部関数について表示されます。同じ SQL ステートメントから同じ関数が複数回呼び出された場合は、統計が集計されます。

    • 合計呼び出し数 --- 外部関数が呼び出された回数。(行が分割されるバッチの数、再試行の数(一時的なネットワークの問題がある場合)などにより、 SQL ステートメントのテキスト内にある外部関数呼び出しの数とは異なる場合がある。)

    • 送信された行数 --- 外部関数に送信された行数。

    • 受信した行数 --- 外部関数から受信した行数。

    • 送信バイト数(x地域) --- 外部関数に送信されたバイト数。ラベルに「(x地域)」が含まれている場合、データは複数の地域に送信されています(請求に影響する可能性あり)。

    • 受信バイト数(x地域) --- 外部関数から受信したバイト数。ラベルに「(x地域)」が含まれている場合、データは複数の地域に送信されています(請求に影響する可能性あり)。

    • 一時的なエラーによる再試行 --- 一時的なエラーによる再試行の数。

    • コールあたりの平均遅延 --- Snowflakeがデータを送信してから返されたデータを受信するまでの呼び出し(コール)あたりの平均時間。

    「一時的なエラーによる再試行」などのフィールドの値がゼロの場合、フィールドは表示されません。

クエリプロファイルによって識別される一般的なクエリの問題

このセクションでは、クエリプロファイルを使用して特定およびトラブルシューティングできる問題の一部について説明します。

「爆発」結合

SQL ユーザーのよくある間違いの1つは、結合条件を提供せずにテーブルを結合する(「デカルト積」になる)、または1つのテーブルのレコードが別のテーブルの複数のレコードと一致する条件を提供することです。このようなクエリの場合、 Join 演算子は、消費するよりも大幅に(多くの場合、桁違いに)タプルを生成します。

これは、 Join 演算子によって生成されたレコードの数を調べることで確認できます。通常、 Join 演算子が多くの時間を消費することにも反映されます。

次の例は、数百のレコードでの入力を示していますが、数十万のレコードでの出力を示しています:

SELECT tt1.c1, tt1.c2
FROM tt1
JOIN tt2 ON tt1.c1 = tt2.c1
 AND tt1.c2 = tt2.c2;
../_images/ui-profile-issues-exploding-joins.png

ALLなしのUNION

SQL では、2組のデータを UNION または UNION ALL 構造のいずれかと組み合わせることができます。それらの違いは、 UNION ALL は単純に入力を連結するのに対し、 UNION は同じことを行いますが、重複排除も行います。

よくある間違いは、 UNION ALLのセマンティクスで十分な場合に UNION を使用することです。これらのクエリは、クエリプロファイルに UnionAll 演算子として表示され、余分に Aggregate 演算子が追加されます(重複排除を実行します)。

大きすぎてメモリに収まらないクエリ

一部の操作(例えば、巨大なデータセットの重複排除など)では、操作の実行に使用されるサーバーで使用可能なメモリ量が中間結果を保持するのに十分でない場合があります。その結果、クエリ処理エンジンはローカルディスクへのデータの 流出 を開始します。ローカルディスクスペースが十分でない場合、流出したたデータはリモートディスクに保存されます。

この流出は、クエリのパフォーマンスに大きな影響を与える可能性があります(特に、リモートディスクが流出に使用される場合)。これを軽減するには、以下をお勧めします:

  • より大きなウェアハウスを使用する(操作に使用可能なメモリ/ローカルディスクスペースを効果的に増やす)、または

  • 小さいバッチでデータを処理します。

非効率なプルーニング

Snowflakeは、データに関する豊富な統計を収集し、クエリフィルターに基づいてテーブルの不要な部分を読み取らないようにします。ただし、これを有効にするには、データストレージの順序をクエリフィルター属性と関連付ける必要があります。

プルーニングの効率は、 TableScan 演算子の スキャンされたパーティションパーティションの合計 統計を比較することで確認できます。前者が後者のごく一部である場合、プルーニングは効率的です。そうでない場合、プルーニングは効果がありません。

もちろん、プルーニングは、大量のデータを実際にフィルターするクエリにのみ役立ちます。プルーニング統計にデータ削減が示されていないが、 TableScan の上に多数のレコードを除外する Filter 演算子がある場合、これはこのクエリに対して異なるデータ編成が有益であることを示す可能性があります。

プルーニングの詳細については、 Snowflakeテーブル構造について をご参照ください。