Snowflakeは、クラウド上で提供されるデータウェアハウス(DWH)サービスであり、その革新的なアーキテクチャによって、従来のDWHが抱えていたスケーラビリティ、パフォーマンス、コスト効率の問題を解決しました。Snowflakeは単なるDWHではなく、データ共有やデータアプリケーション開発を可能にする「データクラウド」として位置づけられています。
1. Snowflakeの革新的なアーキテクチャ
Snowflakeの最大の差別化要因は、その独自の「マルチクラスター・シェアードデータ」アーキテクチャです。これは、コンピューティング(処理)とストレージ(保管)の機能を完全に分離し、独立してスケールできるように設計されています。
① ストレージ層(Shared Data)
データは、S3(Amazon S3)やAzure Blob Storageといったクラウドストレージ上に保存されます。データは圧縮され、最適化されたマイクロパーティションとして格納されます。
② コンピュート層(Multi-Cluster Compute)
クエリ処理を行うための仮想マシン(VM)群です。
- 独立したクラスター: 処理能力(ウェアハウス)は、ユーザーやワークロードごとに独立したクラスターとして提供されます。これにより、ある部門の重い処理が、他の部門の処理速度に影響を与える「リソースの競合」が完全に解消されます。
- 自動スケーリング: 必要に応じて自動で処理能力を拡張(スケールアップ・アウト)し、処理が終了すると自動で停止します。これにより、利用したリソースに対してのみ課金が発生します。
③ クラウドサービス層
認証、メタデータ管理、SQLの最適化、セキュリティ、アクセス制御(RBAC)といったサービス全体を管理する頭脳部分です。
2. Snowflakeの主要な機能とメリット
💰 従量課金制による高いコスト効率
Snowflakeの料金体系は、使用したコンピュートリソース(ウェアハウスの稼働時間)とストレージ容量のみに基づく完全な従量課金制です。
- コンピュートとストレージの分離: ストレージ費用は安価に抑えられ、高価なコンピューティングリソースは必要なときに必要なだけ利用できるため、従来のDWHと比較して高いコスト効率を実現します。
📊 データシェアリング(Data Sharing)
Snowflakeの最もユニークな機能の一つです。データをコピーしたり移動させたりすることなく、セキュアな方法でデータを組織内や外部の顧客とリアルタイムで共有できます。
- データマーケットプレイス: Snowflake Data Marketplaceを通じて、サードパーティのデータセットを直接、自分のSnowflake環境に取り込み、すぐに分析に利用できます。
🔄 柔軟なデータ型への対応
構造化データ(テーブル形式)だけでなく、JSON、XML、Parquetなどの半構造化データもそのままの形式で保存・分析できます。これにより、データのETL(抽出・変換・ロード)プロセスを簡素化できます。
3. Snowflakeの活用シーン
| 活用シーン | 概要 |
| データウェアハウス統合 | 従来のオンプレミスDWHからの移行先として、スケーラビリティとコスト効率を向上させる。 |
| データレイクとの統合 | S3などのデータレイクに保存されたデータも、Snowflakeの仮想ウェアハウスを通じてシームレスにクエリ可能。 |
| セキュアなデータ共有 | 取引先やグループ会社間で、データコピーの手間なしに最新データをリアルタイムで共有する。 |
| データアプリケーション開発 | ストリーミングデータ処理やデータサイエンスのワークロードの基盤としても利用する。 |
Snowflakeは、その柔軟なクラウドネイティブな設計により、現代のデータ戦略において中心的な役割を果たすプラットフォームとなっています。
Snowflakeが、AWS S3やAzure Blob Storageといったデータレイク(クラウドストレージ)に物理的に保存されたデータを、あたかも自分自身のデータベースにあるテーブルであるかのように扱えるようにする仕組みです。
💻 1. データレイク連携の仕組み:外部テーブルと仮想ウェアハウス
Snowflakeがデータレイク上のデータにアクセスするプロセスは、以下の3つの要素で構成されます。
① 外部ステージ (External Stage)
- 役割: データレイク内の特定の場所(S3のバケットやフォルダ)への接続情報と認証情報を定義するオブジェクトです。Snowflakeに「この場所を見てデータを取得してね」と教える役割を果たします。
② 外部テーブル (External Table)
- 役割: データレイク上のファイル(Parquet、CSV、JSONなど)にSQLを通じてアクセスするための仮想的なテーブル定義です。
- 特徴: 外部テーブルは、データ自体をSnowflakeの内部ストレージにコピーしません。保存されているのは、ファイルへのメタデータ(ファイル名、パス、サイズ、最終更新日時など)のみです。
- クエリの実行: ユーザーが外部テーブルに対して
SELECTクエリを実行すると、Snowflakeはメタデータを参照し、必要なファイルだけをデータレイクから読み取って処理します。
③ 仮想ウェアハウス (Virtual Warehouse)
- 役割: 外部テーブルから取得したデータを処理するためのコンピューティングリソースです。
- 特徴: データレイクからデータが読み込まれると、その後の集計や結合といったすべての計算処理は、Snowflakeの高速な仮想ウェアハウス上で実行されます。これにより、データレイクに直接クエリを発行するよりも、遥かに高速で柔軟な分析が可能になります。
🔄 2. シームレスにクエリできるメリット
データレイクのデータをSnowflake経由で分析する主なメリットは以下の通りです。
データの移動が不要 (No Data Copying)
Snowflakeの内部ストレージにデータをロード(コピー)するコストと時間を削減できます。データは低コストなS3に保存されたままなので、ストレージコストを抑えつつ、分析が必要な時だけSnowflakeのコンピュート機能を使えます。
DWHとデータレイクの統合分析
データレイクにある大量の生データ(例:Webサイトのログ)と、Snowflake内部に保存されているクリーンな分析用データ(例:顧客マスタ)を、一つのSQLクエリ内で結合して分析できます。これにより、分析の幅が大きく広がります。
データの鮮度維持
外部テーブルは、データレイク上のファイルが更新されると、その変更をほぼリアルタイムに反映できます。データを定期的にロードするバッチ処理を待つ必要がありません。
💻 2. データソース側(DWH)エンジンのメリット・デメリット(例:Snowflake、BigQuery)
データソース側(DWH)のエンジンは、データが格納されている場所で直接、分散処理を行います。
| カテゴリ | メリット |
| データの鮮度 | 最高レベル。データはDWH内の最新のものに直接クエリされるため、リアルタイム性が高い。 |
| データ容量 | 事実上無制限。ペタバイト級の大規模データも処理可能。 |
| パフォーマンス | 安定性に優れるが、インメモリに比べて処理時間は長くなることがある(ただし、現代のクラウドDWHは非常に高速)。 |
| DWH負荷 | 高い。ユーザーが操作するたびにDWHのコンピュートリソースを消費するため、コストが高くなりやすい。 |
| 適したシーン | アドホック分析(自由な探索)、非常に大規模なデータ、およびデータのリアルタイム性が最優先される場合に最適。 |
メトリクス管理
1. Metric Store
Snowflakeは、企業全体でメトリクス(指標)の定義を一元管理し、再利用可能にするためのMetric Store機能の提供を進めています。
- 機能: メトリクスをSQLクエリとして定義し、その定義をSnowflakeのガバナンスとセキュリティフレームワーク内で管理します。これにより、データ変換ロジック(dbtなど)と、最終的なビジネス指標の定義をDWH内で統一できます。
- 目的: LookerのLookMLやAtScaleが提供するセマンティックレイヤーと同じ目標を、Snowflakeのネイティブ機能として実現することを目指しています。
2. Cortex Analyst とその他のAI統合
Cortex Analystは、Snowflakeが提供する生成AIを活用した機能群の一部です。
- 機能: 自然言語処理を通じて、ユーザーが質問するだけでデータに対するインサイトやメトリクスを自動的に生成・分析します。
- メトリクス管理との関連: このようなAI駆動の分析を正確に行うためには、基盤となるデータやメトリクスがMetric Storeを通じて統一的に定義され、信頼できる状態にあることが不可欠となります。
Snowflake Cortex Analystの料金
Snowflakeクレジットの消費:
- Cortex Analystがユーザーの質問を処理し、SQLを生成し、結果を解釈する際に、Snowflakeクレジットが消費されます。
- この消費量は、通常のウェアハウスでのSQL実行とは別に計算されます。
LLM利用料:
- バックエンドで GeminiなどのLLM が使用されるため、LLMのモデル利用にかかる料金が、推論回数や処理されたデータ量に基づいて発生します。
- これは、Snowflakeがユーザーに代わってGoogle CloudなどのAIサービスを呼び出すコストであり、最終的にSnowflakeクレジットを通じてユーザーに請求されます。
🧊 2. Semantic View
Semantic View は、Snowflakeにおける セマンティックレイヤー(意味の層) の概念を実現するために導入された機能です。
📐 概要と役割
Semantic Viewは、Snowflake内の複雑な基盤データ(テーブルやビュー)の上に、ビジネス用語に基づいた「統一されたデータ定義」*を確立するためのビューです。
これは、従来のBIツールのセマンティックレイヤー(LookMLなど)の機能の一部を、Snowflake自体に持たせることを目指しています。
| 機能 | 特徴 |
| ビジネスロジックの定義 | 「売上」「アクティブユーザー(DAU)」といったKPIの計算ロジックを、このビュー内で一元的に定義します。 |
| 複雑性の抽象化 | データウェアハウスの物理的な複雑な結合(JOIN)やデータクリーニングのロジックを隠蔽し、ユーザーにはシンプルな指標とディメンションだけを見せます。 |
| 一貫性の確保 | すべてのBIツールや分析アプリケーションがこのSemantic Viewを参照することで、全社的に指標の定義がブレない状態を確立します。 |
💡 価値
Semantic Viewは、前述の Cortex Analyst がSQLを生成する際の「コンテキスト辞書」としても機能します。AIは、このSemantic Viewを参照することで、複雑なテーブル構造を知らなくても、ビジネスにとって正しい定義(メトリクス)に基づいたSQLを生成できるようになります。
これにより、「自然言語での質問」→「統一されたメトリクスに基づくSQL生成」→「高速な分析」という一連の流れが、Snowflakeのエコシステム内でよりスムーズに実現されます。
Workspaces
Snowflake Workspacesは、Snowflake上でリポジトリ全体を編集・実行(※SQLのみ)できるIDEです。
主な特徴
- ブラウザベースのIDE
- 追加のソフトウェアインストール不要(外部IDEを組織で導入する必要がない)
- Snowflakeのアカウントにログインできるところならどこでも開発できる
- Git統合
- GitHub、GitLabとの連携が可能(一部GitHubのみの機能あり)
- 基本的なGit処理をノーコマンドで実行可能
- 多言語対応
- SQL、Python、JavaScript、Markdown等に対応(対応言語だとハイライト機能あり。.mdファイルにプレビュー機能もついている。実行ができるのは現状SQLのみ)
- Snowflakeのデータソースとの統合
- データベースへの直接アクセス
- SQLクエリの実行結果をIDE内で確認
わざわざ組織のメンバー全員に外部IDEの環境設定をしなくてもいいというところが開発者にとっていいところでしょうか。ローカルPCのマシンスペックにも依存しませんしね。
往々にして開発プロジェクトにアサインされた際の環境構築に1営業日かかることもあるので、Snowflakeユーザーを作成すればすぐに開発にジョインできるというのもメリットなのではないでしょうか。
マルチクラスターウェアハウス
Snowflakeのマルチクラスターウェアハウスとは、一言でいうと「混雑時に、同じサイズの計算リソースを自動で横に並べて増やす機能」のことです。
通常のウェアハウス(シングルクラスター)が「1台のサーバー」だとすれば、マルチクラスターは「必要に応じて最大10台まで増えるタクシーの行列」のようなイメージです。
1. なぜマルチクラスターが必要なのか?
Snowflakeには2種類のスケーリング(拡張)があります。この違いを理解するとマルチクラスターの役割が明確になります。
| 拡張の種類 | 呼び方 | 目的 | 例え |
| サイズ変更 | スケールアップ | 1つの重いクエリを速くしたい時 | 軽トラを大型トラックに変える |
| マルチクラスター | スケールアウト | 大量の同時クエリを捌きたい時 | 軽トラの「台数」を増やす |
朝の始業直後など、多くのユーザーが一斉にダッシュボードを開くと、シングルクラスターでは「順番待ち(キュー)」が発生します。マルチクラスターを設定しておけば、Snowflakeが自動でクラスターを増やして並列処理を行うため、待ち時間をゼロにできます。
2. 動作モードと設定
マルチクラスターウェアハウスを設定する際は、「最小クラスター数」と「最大クラスター数」を指定します。
① 自動スケールモード(推奨)
「最小 < 最大」で設定します(例:最小1、最大5)。
- 負荷増: 既存のクラスターが埋まると、2台目、3台目…と自動で起動します。
- 負荷減: クエリが減ると、不要なクラスターを自動で停止し、コストを抑えます。
② 最大化モード
「最小 = 最大」で設定します(例:最小5、最大5)。
- 常に指定した台数が動くため、ピーク時への備えは万全ですが、その分クレジットを消費し続けます。
3. スケーリングポリシー(出し入れの性格)
クラスターをいつ増やし、いつ減らすかの「性格」を2種類から選べます。
- Standard(標準): 「ユーザーを待たせない」ことを優先。クエリが溜まったらすぐに次を起動します。
- Economy(エコノミー): 「節約」を優先。既存のクラスターが十分に活用され、かつ新しいクラスターを起動しても数分間は使い続ける見込みがある時だけ起動します。
4. 注意点
- プラン: この機能は Enterprise Edition 以上 でのみ利用可能です。
- コスト: 起動しているクラスターの台数分だけクレジットを消費します。
- 例:Sサイズ(1クレジット/時)で3台動けば、1時間あたり3クレジット消費。
Snowflakeのウェアハウスは、サイズが1つ上がるごとに「計算能力が2倍」になり「1時間あたりのコストも2倍」になります。
Snowflakeの理想的なスケーリングは「サイズを2倍にしたら、時間は半分になる(コストは変わらない)」という状態です。
「ウェアハウスを大きくしても時間が半分にならない」という現象が起きたら、それはサイズを上げる限界のサインです。
| サイズ | クエリ時間 | 消費クレジット(目安) | 処理効率 |
| M (4台) | 10分 | $4 \times 10/60 = 0.66$ | 基準 |
| L (8台) | 5分 | $8 \times 5/60 = 0.66$ | 理想的(時間は半分、コスト不変) |
| XL (16台) | 2分40秒 (160秒) | $16 \times 160/3600 \approx 0.71$ | 良好(ほぼ理想に近い) |
| XXL (32台) | 1分40秒 (100秒) | $32 \times 100/3600 \approx 0.88$ | 非効率(コストが増大し始めている) |
- MからLへの変更: 時間がちょうど半分(10分→5分)になっています。これは「線形スケーリング」と呼ばれ、コストを変えずに待ち時間だけを減らせた最高の状態です。
- LからXLへの変更: 理想は2分30秒ですが、実際は2分40秒です。わずかに効率は落ちていますが、「10秒の誤差で待ち時間をさらに半分近くまで減らせる」ため、実運用では非常に投資価値が高いです。
- XLからXXLへの変更: 理想は1分20秒ですが、実際は1分40秒かかっています。ここでは「並列処理のオーバーヘッド」が発生し始めており、払うお金の割にスピードが上がらなくなっています(収穫逓減)。
ビューについて
通常のビューは便利ですが、定義(SQLの中身)がユーザーに見えてしまったり、特定の最適化によって見せてはいけないデータが推測されたりするリスクがあります。それを防ぐのが「セキュア」という設定です。
1. セキュアビュー(SECURE VIEW)とは?
通常の CREATE VIEW の代わりに、SECURE キーワードを付けて作成します。
CREATE OR REPLACE SECURE VIEW my_secure_view AS
SELECT ID, NAME, SALARY
FROM employees
WHERE department = 'Sales';保護される2つのポイント
① ビューの定義(SQL)の隠蔽
通常のビューは、権限があれば GET_DDL 関数などで「どういうSQLで書かれているか」を誰でも見ることができてしまいます。セキュアビューにすると、ビューの所有者(OWNER権限を持つロール)以外は、その定義を見ることができなくなります。
② クエリ最適化によるデータ推測の防止
Snowflakeの強力な最適化エンジンは、通常、効率よくデータを出すためにクエリを書き換えます。しかし、これにより「エラーメッセージ」などを通じて、本来 WHERE 句で除外されているはずのデータの存在(例:給与の範囲など)を推測できてしまうサイドチャネル攻撃のリスクがあります。 セキュアビューにすると、こうした推測を許すような最適化をあえて制限し、データの安全性を優先します。
2. 実務で使われる関連DDL・操作
システム開発の現場では、データベースのテーブルをGUI(マウス操作)で作るのではなく、SQLファイルを書いて実行します。このファイルを「DDLスクリプト」と呼び、プログラムのソースコードと同じように管理します。
既存のビューをセキュアに変更する
既に作成済みのビューを後から保護することも可能です。
ALTER VIEW my_view SET SECURE;権限の管理(GRANT / REVOKE)
ビューを保護しても、誰にそれを見せるかを制御しなければ意味がありません。
-- ロールに対して、ビューの「参照権限のみ」を与える
GRANT SELECT ON VIEW my_db.my_schema.my_secure_view TO ROLE analyst_role;通常のビューとセキュアビューの比較
| 特徴 | 通常のビュー | セキュアビュー |
| 定義の表示 | 権限があれば誰でも見れる | 所有者(OWNER)のみ見れる |
| パフォーマンス | 最大化される | セキュリティ優先のため、わずかに低下する場合がある |
| デバッグ | 実行計画が見えるので容易 | 中身が隠されるため、トラブルシューティングが難しい |
| 主な用途 | 共通の計算ロジックの共有 | 外部組織や特定部署へのデータ公開 |
標準ビューとマテリアライズドビューの比較
マテリアライズドビューは、簡単に言うと「計算済みのキャッシュ」のようなものです。
標準ビュー(View)が「実行するたびに中身を計算するレシピ」だとしたら、マテリアライズドビュー(Materialized View / 通称:マテビュー)は「すでに料理して保存してある作り置き」です。
| 特徴 | 標準ビュー | マテリアライズドビュー |
| データの実体 | なし(ただのショートカット) | あり(物理的に保存される) |
| 実行速度 | 毎回計算するので中速 | 計算済みなので超高速 |
| データの鮮度 | 常に最新 | 設定により更新(同期)が必要 |
| コスト | クエリ実行時の計算費用のみ | 保存費用(ストレージ)と自動更新費用がかかる |
| 主な用途 | 複雑なSQLの共通化 | 頻繁に使う重い集計処理の高速化 |
例えば、数億件の売上データから「店舗別・月別の売上集計」を出すSQLがあるとします。
- 普通のビューの場合: 誰かがアクセスするたびに、毎回数億件のデータをかき集めて合計を出します。これでは表示に数分かかってしまいます。
- マテビューの場合: 夜中などに1回だけ計算して、その結果を別のテーブルのように保存しておきます。ユーザーが見るときは、計算済みの「数行〜数百行の結果」を見るだけなので、0.1秒で終わります。
Snowflakeのテーブルタイプ
Snowflakeのテーブルタイプは、データの保存期間、コスト、用途(分析か運用か)によって使い分けます。ご指摘の通り、HybridテーブルだけがOLTP(トランザクション処理)向けに設計されているのが大きな特徴です。
主要なテーブルタイプについて、それぞれの性質を整理して解説します。
1. Permanentテーブル
Snowflakeのデフォルトのテーブルタイプです。
- 特徴: すべての保護機能(Time Travel と Fail-safe)が有効です。
- Time Travel: 最大90日間(Enterprise以上)。
- Fail-safe: 7日間のデータ保護期間(Time Travel終了後に開始)。
- 用途: 本番環境の重要なデータ、消えてはいけない基幹データ。
2. Transientテーブル
「一時的」という意味ですが、セッションを閉じても削除されません。
- 特徴: Fail-safeがないため、ストレージコストを抑えられます。
- Time Travel: 最大1日間。
- 用途: ETL処理の中間データなど、万が一消えても再作成可能なデータ。
3. Temporaryテーブル
セッション中のみ存在する、最も寿命の短いテーブルです。
- 特徴: セッションが終了すると自動的に削除されます。同じ名前のPermanentテーブルがあっても、セッション内ではこちらが優先されます。
- 用途: 複雑なクエリの一時的な計算用、ユーザーごとの作業用。
4. Dynamicテーブル
「テーブル」という名前ですが、ストリーム処理と変換を自動化する新しいタイプです。
- 特徴:
CREATE DYNAMIC TABLE ... AS SELECT ...で定義し、指定した「ラグ(鮮度)」に合わせてSnowflakeが自動でデータを更新します。 - 用途: 複雑なデータパイプラインの簡素化(タスクやストリームを自分で組む代わりに使用)。
5. Externalテーブル
Snowflakeの外(S3やAzure Blob等)にデータがある状態のテーブルです。
- 特徴: Snowflake内にはメタデータ(場所の情報)のみを持ち、実データはクラウドストレージに置いたまま参照します。
- 用途: 大容量のログファイルをロードせずに検索したい場合や、他システムと共有しているデータの参照。
6. Hybridテーブル
Unistoreという機能の一部で、唯一のOLTP対応テーブルです。
- 特徴: 行ストアと列ストアの両方を持ち、1桁ミリ秒単位の高速なルックアップ(主キー検索)が可能です。
- 一意性制約(UNIQUE)や参照整合性(FOREIGN KEY)を強制できます。
- 用途: アプリケーションのバックエンド、注文管理、在庫確認など、頻繁な単一レコードの更新・参照。
7. Icebergテーブル
オープンソースのテーブルフォーマット「Apache Iceberg」を利用したタイプです。
- 特徴: データの実体は自分のクラウドストレージ(S3等)にParquet形式で保存されますが、Snowflakeのテーブルとして管理・操作できます。
- 用途: データレイクのオープン性を維持しつつ、Snowflakeの性能を享受したい「相互運用性」重視のケース。
8. Directoryテーブル
ステージング領域(ファイル置き場)にあるファイルを「テーブル形式」で見せるものです。
- 特徴: ファイルのURL、サイズ、最終更新日時などのメタデータをクエリできます。
- 用途: 非構造化データ(画像、PDF、音声など)の管理や処理のトリガー。
Snowflake関数

パフォーマンス向上
1. WHERE句をできるだけ早い段階で使用する理由
結論から言うと、「処理対象のデータ行(レコード数)を、最初のステップで最小限に絞り込むため」です。
メモリとCPUの節約
SQLの内部処理では、テーブルを結合(JOIN)したり、並べ替え(ORDER BY)たりする前にデータをメモリ上に読み込みます。
- 悪い例: 100万件のデータをすべて結合してから、最後に10件に絞り込む。
- 良い例: 最初に100万件を10件に絞り込んでから、その10件に対して結合を行う。
後者の方が、DBサーバーが使うメモリ消費量や中間データの作成にかかる時間を劇的に削減できます。
実行順序(クエリの評価順序)の意識
標準的なSQLの実行順序は以下の通りです。
- FROM / JOIN
- WHERE(← ここで絞るのが最速)
- GROUP BY
- HAVING
- SELECT
- ORDER BY
特にHAVING句は「集計後」に絞り込みを行うため、WHEREで代用できる条件(集計関数を使わない条件など)をHAVINGに書くと、無駄な集計処理が走ってしまい低速になります。
2. 列に対して関数を適用させない理由
これは、「B-Treeインデックス(索引)が使えなくなるから」というのが最大の理由です。
インデックスの仕組みと崩壊
データベースのインデックスは、辞書のように「あいうえお順」でデータが整理されている状態です。しかし、列に関数を通してしまうと、その順番が崩れてしまいます。
具体例: 登録日(
created_at)にインデックスが貼ってある場合
- ❌ 遅いSQL:
WHERE TRUNC(created_at) = '2023-10-01'
- 理由:すべての行の
created_atに対して関数を適用して計算し直さないと比較できないため、インデックスを無視して全件検索(フルスキャン)になります。- ⭕ 速いSQL:
WHERE created_at >= '2023-10-01 00:00:00' AND created_at < '2023-10-02 00:00:00'
- 理由:列をそのまま(生の状態)で比較しているため、インデックスを使って高速に場所を特定できます。

左辺を「裸」にする
パフォーマンス改善の合言葉は「左辺を裸にする」です。
- 計算式:
WHERE salary * 1.1 > 300000よりもWHERE salary > 300000 / 1.1 - 文字列操作:
WHERE SUBSTR(zip_code, 1, 3) = '100'よりもWHERE zip_code LIKE '100%'
このように、検索条件の「左側(カラム側)」には何も加工を加えず、右側の定数側で計算を済ませるのが鉄則です。
EXPLAINとクエリプロファイルでボトルネックを特定する
SQLを書いたものの、「なぜか実行が遅い」と感じることはありませんか? パフォーマンス改善の第一歩は、データベースが内部でどのように動いているかを可視化することです。
1. EXPLAINとは:実行前の「設計図」を確認する
EXPLAINコマンドを実行すると、実際にクエリを走らせることなく、DBエンジンが計画している実行プランを確認できます。
ここで注目すべきは、最新のオプティマイザの賢さです。例えば、ベースとなるテーブル(Table)の代わりにマテリアライズドビューが定義されている場合、オプティマイザはコンパイル時に「こちらを使ったほうが効率が良い」と自動で判断し、参照先を差し替えてくれることがあります。
- コンパイル時の最適化: プログラミングのコンパイルと同様、SQLも実行前に「どう動くのが最短か」が計算されます。
- 効率的なパスの選択: インデックスの有無や統計情報に基づき、最もコストの低いルートが選ばれます。
2. クエリプロファイル:実行後の「成績表」を読み解く
クエリプロファイルは、実行されたクエリの各ステップ(ノード)の処理結果を視覚化したものです。
下から上へ流れる処理の順序
クエリプロファイルのノードは、一般的に下から上へ順番に処理が行われます。
- 一番下のノード(Table Scanなど)でデータを読み込む。
- 中間ノード(FilterやJoinなど)で加工・結合する。
- 一番上のノードで結果を出力する。
どこかのノードで処理時間が異常に長い場合、そこがボトルネックです。
Most expensive nodes
実行に最も時間がかかったノードが表示される。
Profile overview
プロファイル全体(Overview)を確認する際、特に重要な指標が2つあります。
- Processing:CPUによるデータ処理に費やされた時間の割合。
- Remote disk:リモートディスクアクセスによって処理がブロックされた時間の割合
- Initialization:クエリ処理の設定に費やされた時間の割合
Statistics
① スキャンの効率性とプルーニング
「Total Partitions に対して Scanned Partitions がどれだけ小さいか」を確認してください。
- 理想的な状態: 大量のデータがあっても、必要な箇所だけを読み込んでいる(プルーニングが効いている)。
- 改善が必要な状態:
TotalとScannedがほぼ同じ。これは、不要なデータまでフルスキャンしていることを意味し、コストと時間の浪費に直結します。
② 危険信号「Bytes Spilled(メモリ溢れ)」
プロファイルに “Bytes Spilled to Local/Remote Storage” という項目が表示されていたら要注意です。
これは、計算に使用するメモリ(RAM)が不足し、一時的なデータをローカルSSDやリモートストレージに書き出した(退避させた)ことを示します。これを「Spilling」と呼びます。
仮想ウェアハウスで大きなデータの「ソート(ORDER BY)」「結合(JOIN)」「集計(GROUP BY)」などを行う際、Snowflakeはまずメモリ内で処理しようとします。しかし、処理対象のデータがメモリ容量を超えると、一時的な置き場としてディスクを使わざるを得なくなります。
- なぜ遅いのか: メモリ上での計算に比べ、ストレージへの書き込み・読み込みは極端に低速です。
- 対策: 仮想ウェアハウスのサイズを上げる(メモリを増やす)か、処理対象のデータ量をWHERE句で絞り込む検討が必要です。
ローカルスピル(Local Spilling)
メモリから溢れたデータが、仮想ウェアハウスを構成するサーバー(ノード)に直接搭載されているローカルSSDに書き出される状態です。
- 影響: メモリ(RAM)に比べると読み書き速度が落ちるため、クエリの実行速度が低下します。
- 例え: 机(メモリ)が書類でいっぱいになったので、すぐ足元の引き出し(ローカルSSD)に一時的に書類を避難させて作業を続けている状態です。
リモートスピル(Remote Spilling)
ローカルSSDの容量までもがいっぱいになり、さらにデータが溢れて、遠くにあるクラウドストレージ(S3 / Azure Blob / GCS)に書き出される状態です。
- 影響: ネットワーク経由でデータをやり取りするため、パフォーマンスは劇的に悪化します。ローカルスピルよりも遥かに時間がかかります。
- 例え: 足元の引き出しも満杯になったので、わざわざ会社から離れた外部の倉庫(リモートストレージ)まで書類を運び、出し入れしながら作業している状態です。
② Percentage scanned from cache
2回目実行した時にキャッシュからスキャンされた割合が100%になる。
これはクエリが必要なデータを全てデータキャッシュから取得したため。
メタデータ
Snowflake は、テーブルを保存するときに 自動でメタデータを保持している。
例(内部的に持っている情報):
- 各マイクロパーティションごとの
- 最小値
- 最大値
- NULL の有無
- 列ごとの統計情報
👉 これらは クラウドサービスレイヤー にキャッシュされている。
④ 今回のクエリが「特別」な理由
MIN(ps_partkey)
MAX(ps_partkey)- 集計対象は 1列のみ
- 必要なのは 最小値と最大値
- これは メタデータだけで分かる
つまり:
「実データ(ストレージ層)を読む必要がない」
1. パーティションプルーニングとは?
一言でいうと、「不要なデータを一切読まずに、最短距離で目的のデータにたどり着く技術」のことです。
「プルーニング(Pruning)」とは、園芸用語で「枝切り」を意味します。大きな木(テーブル全体)から、不要な枝(関係ないデータ)を切り落とし、必要な実(データ)だけを収穫するイメージです。
2. どうやって「不要」だと判断しているの?
Snowflakeのデータは、「マイクロパーティション」という小さな塊に分けて保存されています。
ここが賢いポイントなのですが、Snowflakeの「脳(クラウドサービスレイヤー)」は、各パーティションの中に「どんな値が入っているか」というメタデータ(統計情報)を常に記録しています。
- 記録されている情報の例:
- このパーティションの
注文日の最小値は2024-01-01 - 最大値は
2024-01-15
- このパーティションの
あなたが WHERE 注文日 = '2025-01-01' というクエリを投げたとき、Snowflakeは「あ、このパーティションには2024年のデータしかないから、読む必要はないな!」と、ストレージにアクセスする前に判断して捨ててしまいます。
3. プルーニングがもたらす2つの大きなメリット
① 圧倒的なクエリ速度
数億行あるテーブルでも、実際にスキャン(読み取り)するのが数個のパーティションだけで済めば、処理時間は劇的に短縮されます。
② コストの削減
Snowflakeは「計算リソース(仮想ウェアハウス)」が動いた分だけ課金されます。読み取るデータが減れば、それだけ計算にかかる時間も短くなり、結果として支払うクレジット(お金)を節約できるのです。
4. 性能をさらに引き出すためのコツ
Snowflakeのデータは、基本的に「取り込まれた順(ロード順)」に整理されます。
例えば、毎日日付順にログをロードしていれば、日付によるプルーニングは非常に効率よく効きます。しかし、もし「特定の店舗ID」でよく検索するのであれば、その列を意識してデータを整理しておくことが重要です。
プロのアドバイス: よく使う検索条件(WHERE句)や結合キー(JOIN句)に指定する列が、データの並び順と一致しているか確認しましょう。これにより、より多くのパーティションがプルーニングされ、パフォーマンスが最大化されます。
データのロード
Snowflakeでは、データをロードする前に一時的な置き場(ステージ)を介しますが、そこには「どういうルールでデータを扱うか」という設定情報(プロパティ)が付随しています。
大きく分けて2つの意味がありますので、具体的に解説します。
1. ステージそのものの「設定(定義)」を確認する
ステージを作成した際のDDL(設定内容)を確認することです。
- 何を確認するのか?:
- ステージの場所(S3のパスなど)
- アクセスするための認証情報
- ファイルフォーマットの指定(CSVか、JSONかなど)
- 使うコマンド:
DESC STAGE my_s3_stage;- これで、ステージに紐付いているURLや、どんなコピーオプションが設定されているかという「プロパティ(属性)」が一覧で表示されます。
2. ステージにある「ファイルの情報」を確認する
「ステージという場所のプロパティ」というよりも、「そこに置かれているファイルのプロパティ」を確認する作業です。
- 何を確認するのか?:
- ファイルの名前、サイズ
- 最終更新日時
- ロードしようとしているファイルが本当に存在するか
- 使うコマンド:
LIST @my_s3_stage;- これを実行すると、ステージ上にあるファイルのリスト(一覧プロパティ)が返ってきます。
3. なぜ確認が必要なのか?(ロードにおける重要性)
ロードの失敗を防ぐために、以下のプロパティが整合しているか確認するのが実務上の目的です。
| 確認したい項目 | プロパティでチェックすること |
| 場所の間違い | URL(パス)が正しいか。 |
| ファイル形式 | CSVならカンマ区切りか、ヘッダーはあるか。 |
| エンコーディング | UTF-8か、それともShift-JISか。 |
| 圧縮状態 | gzipなどで圧縮されているか。 |
SELECT $1
FROM @training_db.traininglab.ed_stage/load/lab_files/(PATTERN=> 'region[.]tbl$');SELECT $1: Snowflakeでは、ステージ上のファイルを直接参照する場合、列名を指定する代わりに$1,$2,$3(1番目の列、2番目の列…)という記号を使います。FROM @ステージ名/パス/: テーブルの代わりに、ステージ上のディレクトリを指定しています。(PATTERN=> 'region[.]tbl$'): 正規表現を使って、読み込むファイルを絞り込んでいます。この場合、「最後がregion.tblで終わるファイル」だけを対象にしています。
2. なぜ結果が「1つの列」にまとまってしまうのか?
解説文にある通り、表示されたデータが 0|AFRICA|... のように1行丸ごと1列目($1)に入ってしまっているのは、Snowflakeのデフォルト設定(プロパティ)が「カンマ(,)」を区切り文字だと信じ込んでいるからです。
仕組みの解説:
- Snowflakeの期待: ステージの設定(FILE_FORMAT)がデフォルトのままだと、「カンマがあったら次の列($2)に分けよう」と準備して待っています。
- ファイルの実態: しかし、実際のファイルは
0|AFRICA|...と、**パイプ(|)**で区切られています。 - 結果: Snowflakeは「行の最後まで探したけど、どこにもカンマ(,)がないぞ。じゃあ、この行全体が『1番目の列($1)』なんだな」と判断し、1つの長い塊として出力してしまいます。
3. 「同じステージではステージ化できるが…」の意味
解説文のこの部分は、「置くこと(PUT)」と「読むこと(COPY/SELECT)」は別物だということを警告しています。
- ステージ化(Stage): ステージは単なる「ファイル置き場(フォルダ)」です。中身がCSVだろうが、パイプ区切りだろうが、Excelだろうが、置くこと自体は自由です。
- ロード・クエリ(Load/Query): 中身を読み取ってテーブルに入れようとしたり、
SELECTで中身を見ようとしたりする瞬間、Snowflakeは「このファイルはどういうルールで読めばいいの?」という情報を必要とします。
ここで設定(ファイルフォーマット)が間違っていると、データがぐちゃぐちゃに入力されたり、エラーでロードが止まったりします。
4. ファイルフォーマットの指定
-- パイプ区切り用の「指示書(ファイルフォーマット)」を作成
CREATE OR REPLACE FILE_FORMAT my_pipe_format
TYPE = 'CSV'
FIELD_DELIMITER = '|' -- ここでパイプを指定
SKIP_HEADER = 1;
-- その指示書を使ってクエリを投げると、$1, $2, $3 に正しく分割される
SELECT $1, $2, $3
FROM @ed_stage/load/lab_files/
(FILE_FORMAT => 'my_pipe_format', PATTERN => 'region[.]tbl$');- 設定(AUTO_DETECT_COMPRESSION): 圧縮形式を指定しない(デフォルトの
AUTO設定)
この設定にすると、Snowflakeは非常に賢い動きをします。
- まず、ファイルの先頭(マジックナンバー)を見て、「これはGzipかな? それとも生データかな?」と自分で判断します。
- 「生データだ」と判断すれば、そのまま読みます。
- 「Gzipだ」と判断すれば、その場で自動的に解凍しながら読みます。
| ファイルの実態 | 設定(FILE_FORMAT) | 結果 | 理由 |
| 生データ (CSV) | GZIP | 失敗 ❌ | 圧縮されていないのに解凍しようとしてエラー。 |
| Gzipデータ | NONE (圧縮なし) | 失敗 ❌ | 圧縮されたまま読もうとして、文字化けやエラーに。 |
| 生データ (CSV) | AUTO (自動検出) | 成功 ✅ | そのまま読めると判断したため。 |
| Gzipデータ | AUTO (自動検出) | 成功 ✅ | 自動で解凍が必要だと判断したため。 |
検証モード(VALIDATION_MODE)とは?
データを実際にテーブルに放り込む前に、「このファイル、今のテーブル定義でちゃんと入るかな?」とリハーサル(予行演習)をするための機能です。
通常、COPY INTO を実行するとデータがテーブルに書き込まれます。しかし、VALIDATION_MODE オプションを付けると、Snowflakeの動きが変わります。
- 実際にロードしない: テーブルにデータは一切入りません。
- エラーチェックだけ行う: ファイルの中身をスキャンして、エラー(型の不一致、桁あふれなど)がないかを確認します。
- RETURN_ALL_ERRORS: 見つかったすべてのエラーを画面に報告せよ、という指示です。
「結果が生成されませんでした」の本当の意味
SQLを実行して「結果が生成されませんでした(Query produced no results)」と出ると、一見失敗したように感じますが、検証モードにおいては「大成功」のサインです。
- 意味: 「エラーを返せ(RETURN_ALL_ERRORS)」と命令したのに「何も返ってこなかった」=「報告すべきエラーが1つもなかった」ということです。
- 結論: このファイルは今のテーブルに完璧にロードできる状態であることが証明されました。
なぜ「RETURN_ALL_ERRORS」を使うのか?
ON_ERROR = CONTINUE(エラーがあっても無視して進める)を使っていた場合、どこかに「読み飛ばされた不正な行」が隠れている可能性があります。
VALIDATION_MODE = RETURN_ALL_ERRORS を使えば、「過去に無視してしまったエラーも含めて、このファイルのどこが悪いのか全部リストアップして」とお願いできるため、データのクレンジング(掃除)に非常に役立ちます。
ストアドプロシージャ
Snowflakeでデータパイプラインを構築していると、「複数のSQLを順番に実行したい」「条件によって処理を分岐させたい」といった場面に遭遇します。
そんな時に欠かせないのが「ストアドプロシージャ」です。
1. ストアドプロシージャとは?
ストアドプロシージャとは、「一連の処理手順(SQL文の集まりなど)を一つにまとめて、名前を付けて保存したもの」です。
単なる計算(関数)ではなく、「アクション(行動)」を起こすための仕組みだと考えてください。
主な特徴
- 管理アクションの実行: テーブルの作成、データのロード、古いデータの削除など、データベースの操作全般が行えます。
- 動的な制御: 「もしエラーが起きたらこの処理をする」「テーブルリストを取得してループ処理する」といったプログラム的な動きが可能です。
- 言語の選択: SQLだけでなく、Python、JavaScript、Java、Scalaなどで記述できます。
2. 【重要】UDF(関数)とプロシージャの違い
ここが一番の混乱ポイントですが、決定的な違いは「目的」と「呼び出し方」にあります。
| 特徴 | ユーザー定義関数 (UDF) | ストアドプロシージャ |
| 主な目的 | 値を計算して返す(計算機) | 処理を実行する(ロボット) |
| 戻り値 | 必須(1つの値、または1つの表) | 任意(ステータスメッセージなど) |
| SQL操作 | SELECTがメイン(DDL等は不可) | CREATE, DROP, COPYなど何でも可 |
| 呼び出し方 | SELECT function(...) | CALL procedure(...) |
3. どんな時に使うの?(活用シーン)
- 定期的なクレンジング: 毎日深夜に、30日以上前のログデータを別のテーブルへ移動させる。
- 複雑なデータロード: ステージにあるファイルをチェックし、成功したらテーブルAへ、失敗したらエラー通知用テーブルBへ書き込む。
- 動的なSQLの生成: 引数で受け取ったテーブル名に対して、動的にインデックスを再構築する。
プロシージャの役割:環境の「自動セットアップ」
通常、テーブルを作成するには CREATE TABLE 文を実行しますが、この演習ではそれをプロシージャ CREATE_NATION_TABLE() の中に閉じ込めています。
- 何をしているか: 元のデータベース(
SNOWBEARAIR_DB)からデータを引っ張ってきて、「本番用テーブル(NATION)」を特定の形(リージョン名を含む形)で作り直すという作業を自動化しています。 - なぜ便利か: 演習中に何度もテーブルをリセット(再作成)する必要があるため、長いSQLを毎回打つ代わりに
CALL CREATE_NATION_TABLE();と1行打つだけで、いつでも全く同じ初期状態に戻せるようになっています。
2. なぜ UDF(関数)ではなくプロシージャなのか?
ここが最大のポイントです。以前解説した通り、UDFにはできないことが、このコードには含まれています。
- DDL(データ定義言語)の実行: このコードの中では
CREATE OR REPLACE TABLE(テーブルの作成・上書き)を行っています。Snowflakeのルールでは、UDFの中でテーブルを作ったり削除したりすることはできません。 データベースの構造を「操作(アクション)」するためには、必ずストアドプロシージャが必要になります。
コードの注目すべきポイント
① 言語(LANGUAGE SQL)
LANGUAGE SQLSnowflakeスクリプト(SQL)で書かれています。以前はJavaScriptが主流でしたが、現在は使い慣れたSQLの構文でプロシージャを書けるようになり、習得が容易になりました。
② 実行ブロック(BEGIN – END)
BEGIN
...(処理)...
RETURN '...';
END;プロシージャの中身を BEGIN と END で囲むことで、「ここからここまでがひとまとまりの処理ですよ」と定義しています。
③ 戻り値(RETURNS VARCHAR)
RETURNS VARCHAR NOT NULL「計算結果」を返すのではなく、「処理が成功したかどうか」というメッセージを返すために文字列(VARCHAR)を宣言しています。実行後に「Creation of table NATION complete.」と表示されることで、管理者は「無事に終わったな」と安心できるわけです。
| テーブル名 | 役割(通称) | 特徴 |
| NATIONS_NEW | ステージングテーブル | 外部から届いた「新しいデータ」をとりあえず放り込む一時的な場所。まだ未完成。 |
| NATION | 永続テーブル(本番) | きれいに整形され、他のユーザーが分析やレポートに使う**「正解」のデータ**。データが消えないように管理される。 |
「新しく届いたデータを直接 NATION に書き込めばいいのでは?」と思うかもしれませんが、プロの現場でそれをしないのには理由があります。
- データのクレンジング(掃除): 届いたデータにエラーがあるかもしれません。一度「ステージング(NATIONS_NEW)」に入れて中身を確認してから、きれいなデータだけを「本番(NATION)」に移すことで、本番データが汚れるのを防ぎます。
- テーブル結合(JOIN)の処理: 今回のプロシージャ(
CREATE_NATION_TABLE)を見ると、単なるコピーではなくNATIONとREGIONを結合して「地域名」を表示するように加工しています。この「加工」という手間をかけた後の完成品が、本番である「永続テーブル」なのです。
ストアドプロシージャが「工場」の役割
この「ステージング」から「本番(永続テーブル)」へデータを移す作業は、毎回手動でやるとミスが起きます。
そこで、今回学んでいるストアドプロシージャが活躍します。
- プロシージャを実行(CALL)する
- 自動的にステージング(NATIONS_NEW)からデータを取り出す
- 加工(JOINなど)を行う
- 本番(NATION)へ安全に書き込む
このように、プロシージャは「本番環境を常に正しく保つための自動ロボット」のような役割を果たしています。
ユーザーとロール

関数やプロシージャそのものの保持(永続的)
CREATE OR REPLACE FUNCTION や PROCEDURE を実行すると、そのコードはSnowflakeのメタデータ(データベースのカタログ)に登録されます。
- 保持期間: 無期限。
- 削除されるタイミング:
- 明示的に
DROP FUNCTION ...やDROP PROCEDURE ...を実行したとき。 - その関数が含まれている「スキーマ」や「データベース」を削除(DROP)したとき。
- 明示的に
- ワークシートとの関係: ワークシートはあくまで「命令を送るためのエディタ」です。実行ボタンを押した瞬間にSnowflakeのシステム側に書き込まれるため、ワークシートを消しても、書いた中身(ロジック)はデータベース内に残り続けます。
クローニング

タイムトラベル
Snowflakeには「タイムトラベル(Time Travel)」という強力な機能があります。これは、過去の特定の時点のデータを参照できる機能です。
タイムトラベル(過去のデータを参照する機能)を使う際、Snowflakeでは「時間」、「クエリID」、そして「ステートメントID」のいずれかを指定できます。
今回のシナリオでは、以下のような流れを想定しています:
- 時刻をメモする(今回の
SETコマンド) - データを更新したり削除したりする(実験や開発)
- 「あ!失敗した!さっきの時刻の状態に戻したい!」となったとき、メモしておいた変数を使って過去のデータにアクセスする。
保存した変数は、次に説明するようなクエリで呼び出すことができます。
-- さっきメモした時刻(変数の前には $ をつける)のデータを参照する
SELECT * FROM region
AT(TIMESTAMP => $dev_before_changes);1. 時刻(TIMESTAMP)を保存する場合
用途:特定の「時点」を記録したいとき
- メリット: 「お昼休みの前の状態」や「今日の朝9時の状態」など、人間にとって直感的な管理ができます。
- デメリット: Snowflakeのシステム時刻とミリ秒単位でズレる可能性がわずかにあります。
- 使い時: 「これからいろいろな作業(複数のSQL)を始めるぞ」という作業開始前のバックアップポイントとして最適です。
2. クエリID(LAST_QUERY_ID)を保存する場合
用途:特定の「操作」の直前・直後を記録したいとき
ご提示のコードがこちらです。
SET dev_new_europe_regions = LAST_QUERY_ID();- メリット: ピンポイントで正確です。「この更新SQLを実行した直後の状態」を確実に指し示すことができます。
- デメリット: そのクエリが失敗していた場合や、どのクエリIDが何をしたものか後で分からなくなることがあります。
- 使い時: 「さっき実行した
INSERT文の結果を基に、さらに処理を続けたい」など、直前のステップを基準にしたいときに最適です。
具体的にどう使い分ける?
| 保存するもの | コマンド例 | よく使うシーン |
| 時刻 | SET ... = current_timestamp(); | 【保険】 失敗しても「作業開始前」に戻せるようにしておく。 |
| クエリID | SET ... = LAST_QUERY_ID(); | 【検証・差分】 「さっきのデータ追加」で、具体的にどのデータが増えたかを確認したいとき。 |
| コマンド | この演習での役割 |
CLONE ... AT/BEFORE | 過去の特定の時点の状態を、別名のテーブルとして実体化させる。 |
SET ... = LAST_QUERY_ID() | 直前の操作に「しおり」を挟む。後でそこに戻るため。 |
BEFORE(statement => ...) | そのクエリが実行される直前のデータを参照する。 |
UNDROP | 消したテーブルを復活させる。ただし過去の時点指定は不可。 |
ALTER ... RENAME TO | 修正が終わった「仮テーブル」を「本番テーブル」に一瞬で入れ替える。 |



