yokochanです!久々にブログ書きます!
Snowflakeを使っていると「クエリが遅い」という問題に突き当たることがあります。多くの場合、まず試みるのが「ウェアハウスサイズを大きくする」という対処ですが、それで解決しないケースが実は少なくありません。
この記事では、Snowflakeのクエリが遅いと判明したときに何をどの順番で確認すべきかを、Query Profileの読み方とあわせて解説します。ETLツール(Matillionなど)を使っている方にも参考になる内容です。
なぜ「ウェアハウスを大きくしても速くならない」のか?
ウェアハウスのサイズを上げると追加されるのはCPUとメモリです。しかし、クエリの遅さがCPUやメモリの不足以外が原因の場合、サイズを上げても効果がありません。
ウェアハウスサイズアップが有効なのは、メモリ不足によるスピル(一時ディスクへの書き込み)が発生しているときに限られます。それ以外の原因には別のアプローチが必要です。
代表的な「サイズアップが効かない原因」は以下の4つです。
- スキャン量が多い:WHERE句がパーティションキーを使っておらず、不要なデータまで読み込んでいる
- データ転送量が多い:大量のカラムの引き回しや、同一テーブルへの複数回JOINが発生している
- クエリ設計の問題:深いネスト構造や早期フィルタリングの未実施
- 同時実行数の問題:クエリがキューに溜まっており、サイズよりもクラスタ数を増やす必要がある
まず確認する:Query Profile
SnowflakeにはQuery Profileという標準搭載の診断ツールがあります。クエリが遅い原因を特定するための最初の手がかりです。
Query Profile の開き方
- Snowsight にログイン
- 左メニューの Activity をクリック
- Query History を選択
- 遅いクエリをクリック
- Query Profile タブを選択
Query Profile で確認できる主な指標
| 確認項目 | 意味 | 問題のサイン |
|---|---|---|
| Processing % | 計算処理にかかった時間の割合 | 大部分を占めていたら計算が重い |
| Network communication % | ノード間データ転送の割合 | 高い = JOINや集計でデータが大量移動 |
| Bytes Spilled to Remote | リモートディスクに流出したデータの量 | 0以外 = メモリ不足。大きいと特に深刻 |
| Partitions Scanned / Total | 実際に読んだパーティションの割合 | 比率が高い = プルーニングが効いていない |
| Bytes sent over network | ネットワーク越しに転送されたデータ量 | 数GB以上 = JOIN・集計の設計を見直す |
| Percentage scanned from cache | キャッシュから読んだ割合 | 高い = 実は再計算していない(問題なし) |
診断フローチャート:原因の特定手順
Query Profileを開いたら、以下の順番で確認していきます。上位のチェックで原因が特定できたら、それ以降は確認不要です。
各原因と対策の詳細
① パーティションプルーニングが効いていない
Snowflakeはデータを「マイクロパーティション」という単位で保存しています。クエリのWHERE条件がパーティションキー列と一致すると、不要な部分を読み飛ばせます(プルーニング)。これが機能していないと大量のデータを無駄に読み込みます。
確認方法:Query ProfileのStatisticsで Partitions Scanned / Partitions Total の比率を確認します。
対策:
- WHERE句に日付や区分など、パーティションキーとなる列を含める
- テーブルにCluster Keyを設定する(よく絞り込みに使う列を指定)
-- クラスタリングキーの設定例
ALTER TABLE sales_data CLUSTER BY (sale_date, region_id);
② Bytes Spilled to Remote が大きい(メモリ不足)
処理するデータがウェアハウスのメモリに収まらないと、一時的にストレージへの書き出し(スピル)が発生します。ディスクアクセスはメモリより桁違いに遅いため、クエリが大幅に遅くなります。
この場合に限り、ウェアハウスサイズアップが有効です。XSをMやLにするなど、メモリを増やすことでスピルがなくなり、大幅な改善が見込めます。
③ Bytes sent over network が大きい(データ転送過多)
Snowflakeは複数のノードで並列処理します。JOINやGROUP BYでノード間をデータが行き来するとき、転送量が多いと時間がかかります。ウェアハウスを大きくしてもノード間転送量は変わらないため、サイズアップでは解決しません。
対策:
- JOINの前に不要な行をWHEREで絞り込む
SELECT *をやめて必要な列だけ取得する- 大きいテーブル同士のJOINは結合キーやフィルタ条件を見直す
- 複雑な処理は中間テーブルに分割して段階的に処理する
④ キュー待ちが発生している(同時実行数の問題)
Query ProfileでQueued %が高い場合、クエリ自体は速くても順番待ちで時間がかかっている状態です。この場合はウェアハウスサイズアップではなく、マルチクラスタウェアハウス(同じウェアハウスを複数のクラスタで並列稼働させる設定)で解消できます。
ETLツールを使っている場合の注意点
MatillionやdbtなどのETLツール、TableauやLookerなどのBIツールからクエリが発行される場合、自動生成されたSQLが非効率なパターンを含むことがあります。
ツール側の設定やコンポーネント構成を見直すことで、発行されるSQLを改善できることが多くあります。Query Profileで原因を特定した上で、ツール側の設定に立ち返って確認してみてください。
まとめ:対策の選び方チートシート
| 原因 | 主な対策 | ウェアハウス変更は有効? |
|---|---|---|
| スキャン量が多い | プルーニング改善・クラスタリング | ❌ 無効 |
| メモリ不足(スピル) | ウェアハウスサイズアップ | ✅ 有効 |
| ネットワーク転送過多 | クエリ設計の見直し | ❌ 無効 |
| 計算ロジックが重い | クエリ分割・最適化 | △ 限定的に有効 |
| 同時実行数が多い | マルチクラスタウェアハウス | △ サイズより数を増やす |
| キャッシュが効いている | 対処不要 | — 問題なし |
Query Profileを習慣的に確認するだけで、多くのパフォーマンス問題の原因を素早く特定できるようになります。「遅い→サイズアップ」の前に、まずQuery Profileを開くことを習慣にしてみてください。



