はじめに
Snowflakeを触り始めると、最初に戸惑う概念の一つが 「ステージ(Stage)」 です。
「CSVファイルをテーブルに入れたいだけなのに、なぜ一度ステージに置く必要があるの?」
この疑問を持つ方は多いのではないでしょうか。本記事では、ステージが なぜ存在するのか を中心に、その仕組みと種類を整理します。
そもそもステージとは何か
一言でいうと、ステージとは 外部のファイルとSnowflakeテーブルの間に置かれる"中継地点" です。
データをSnowflakeにロードする際、ファイルはまずステージに配置され、そこから COPY INTO コマンドでテーブルに取り込まれます。逆にデータをエクスポートする際も、テーブルからステージへ書き出す流れになります。
ステージはファイルの「置き場所」であり、テーブルではありません。SQLで直接 SELECT することもできますが、データはあくまでファイル形式のまま保持されています。
なぜステージが必要なのか ── 直接ロードではダメな理由
ここが本記事の核心です。ステージが存在する理由は、大きく4つあります。
1. ロードの信頼性を確保するため
大量のデータを一発でテーブルに書き込むのはリスクが高い操作です。ネットワーク障害やファイル破損が途中で起きた場合、テーブルの状態が不整合になりかねません。
ステージという中間層があることで、以下のような段階的な処理が可能になります。
① ファイルをステージにアップロード(失敗しても再送すればよい)
② ステージ上のファイルを検証(VALIDATION_MODE で事前チェック)
③ 問題なければ COPY INTO でテーブルにロード
つまり、ステージは 「ファイルの安全な受け渡し場所」 として機能し、テーブルへの書き込みをアトミック(全か無か)に保つ役割を果たしています。
2. ファイルの事前検証ができるため
COPY INTO コマンドには VALIDATION_MODE というオプションがあり、実際にロードせずにファイルの中身を検証できます。
COPY INTO my_table
FROM @my_stage/data.csv
FILE_FORMAT = (TYPE = 'CSV')
VALIDATION_MODE = 'RETURN_ERRORS';
この機能はステージにファイルが配置されていることが前提です。直接ロード方式では「検証してからロード」というワークフローが成り立ちません。
3. クラウドストレージとの疎結合を実現するため
現実のデータパイプラインでは、ファイルの生成元は多岐にわたります。S3、GCS、Azure Blob Storage、あるいはローカルPCかもしれません。
ステージは、これらの 多様なファイルソースを統一的なインターフェースで扱う抽象レイヤー です。
CREATE OR REPLACE STAGE my_s3_stage
URL = 's3://my-bucket/path/'
CREDENTIALS = (AWS_KEY_ID = '...' AWS_SECRET_KEY = '...')
FILE_FORMAT = (TYPE = 'CSV');
こうしておけば、COPY INTO 側は「どのクラウドのどのバケットか」を意識する必要がなくなります。ストレージの移行や変更があっても、ステージ定義を変えるだけでパイプライン全体を修正せずに済みます。
4. パフォーマンスの最適化のため
Snowflakeはステージ上のファイルに対して以下の最適化を行います。
- 並列ロード: 大きなファイルを分割し、複数のウェアハウスノードで並列に取り込む
- 重複排除: 既にロード済みのファイルを自動でスキップする(64日間のメタデータ保持)
- ファイルフォーマットの統一管理: ステージに紐づけたフォーマット定義を一元管理
重複排除は、ファイル名とメタデータに基づいて動作します。同じファイル名で中身を変えて再アップロードした場合、意図せずスキップされることがあるため注意が必要です。
ステージの3つの種類
Snowflakeには3種類のステージがあり、用途に応じて使い分けます。
| 種類 | 参照方法 | 保存場所 | 主な用途 |
|---|---|---|---|
| ユーザーステージ | @~ |
Snowflake内部(ユーザー専用) | 個人的なアドホック作業 |
| テーブルステージ | @%テーブル名 |
Snowflake内部(テーブル専用) | 特定テーブル専用のロード |
| 名前付きステージ | @ステージ名 |
内部 or 外部(S3/GCS/Azure) | チーム運用・本番パイプライン |
ユーザーステージ(@~)
各ユーザーに自動で割り当てられる個人用の領域です。作成不要でそのまま使えます。
-- ローカルファイルを自分のユーザーステージにアップロード
PUT file:///tmp/data.csv @~;
-- ユーザーステージからテーブルにロード
COPY INTO my_table FROM @~ FILE_FORMAT = (TYPE = 'CSV');
ユーザーステージは手軽ですが、他のユーザーからはアクセスできません。チームでの運用には名前付きステージを使いましょう。
テーブルステージ(@%テーブル名)
テーブルごとに自動で用意されるステージです。そのテーブル専用のファイル置き場として機能します。
-- テーブルステージにファイルを配置してロード
PUT file:///tmp/orders.csv @%orders;
COPY INTO orders FROM @%orders FILE_FORMAT = (TYPE = 'CSV');
名前付きステージ(内部 / 外部)
最も柔軟で、本番運用ではこれを使うのが一般的です。
CREATE OR REPLACE STAGE my_internal_stage
FILE_FORMAT = (TYPE = 'PARQUET');
CREATE OR REPLACE STAGE my_external_stage
URL = 's3://my-data-lake/raw/'
STORAGE_INTEGRATION = my_s3_integration
FILE_FORMAT = (TYPE = 'JSON');
ステージの存在を前提とした機能たち
ステージは単なる「ファイル置き場」にとどまらず、Snowflakeの多くの機能の土台になっています。
- Snowpipe: ステージに新しいファイルが到着したら自動でロードする仕組み。ステージなしには成り立たない
- ディレクトリテーブル: ステージ上のファイル一覧をSQLでクエリできる機能
- データレイクとの連携: 外部ステージを通じて、S3/GCS上のファイルを直接クエリ(外部テーブル)
CREATE OR REPLACE PIPE my_pipe
AUTO_INGEST = TRUE
AS
COPY INTO my_table
FROM @my_external_stage
FILE_FORMAT = (TYPE = 'CSV');
まとめ
Snowflakeにおけるステージは、一見すると面倒な「ひと手間」に見えます。しかし、その存在は以下の恩恵をもたらしています。
| 観点 | ステージがない場合 | ステージがある場合 |
|---|---|---|
| 信頼性 | ロード失敗がテーブルに影響 | ファイル受け渡しとロードが分離 |
| 検証 | ロードしてみないと分からない | 事前にエラーを検出できる |
| 柔軟性 | ストレージごとに処理を変更 | 統一インターフェースで抽象化 |
| 性能 | 重複ロードのリスク | 自動で重複排除・並列処理 |
| 自動化 | 手動トリガーが必要 | Snowpipeで到着即ロード |
ステージは「なぜ直接テーブルに入れられないのか」という不満の対象ではなく、クラウドネイティブなデータパイプラインを安全かつ効率的に構築するための設計思想そのもの です。
まずはユーザーステージ(@~)で手軽に試してみて、慣れてきたら名前付きステージで本格的なパイプラインを組んでみてください。