Snowflakeへのデータ投入は、突き詰めると「ステージにファイルを置き、FILE FORMATで読み方を定義し、COPY INTOで表に流し込む」という3つの部品の組み合わせに集約されます。個々のコマンドは平易ですが、ステージの選び方、エラーの握り方、そしてファイルの分割サイズを外すと、正しく動くのに遅い・高い・落ちるという状態に陥ります。本記事ではAWS上のS3連携を前提に、実務で効く設計判断と、検証段階で先に潰しておくべき落とし穴を整理します。
01ロードの全体像:COPY INTOを軸に3部品で考える
Snowflakeのバルクロードは、SQLコマンド COPY INTO <table> が中心です。この1コマンドが「どこのファイルを(ステージ)」「どう解釈して(FILE FORMAT)」「どのようにエラーを扱いながら(コピーオプション)」表へ書き込むかを一括で指定します。逆に言えば、設計すべきはステージ・FILE FORMAT・コピーオプションの3つに分解できます。まずはこの分解を頭に入れると、後続の判断がぶれません。
データの流れは一方向です。ソースシステムが出力したファイルをステージ(多くはAmazon S3)に配置し、COPY INTOが仮想ウェアハウスの計算資源を使ってファイルを並列に読み、目的のテーブルへ書き込みます。ロード後は誰がいつ何を読んだかがロード履歴として記録され、これが再ロード防止(冪等性)の土台になります。全体像を1枚に落とすと次のとおりです。
02ステージ設計:内部か外部か、AWSではS3外部が基本
ステージはファイルの置き場所です。大別すると内部ステージ(Snowflakeが管理する領域)と外部ステージ(S3・GCS・Azure Blob)があります。内部ステージにはさらに、ユーザーステージ(@~)、テーブルステージ(@%table)、名前付きステージ(@my_stage)があり、SnowSQLの PUT コマンドでローカルファイルをアップロードして使います。小規模な取り込みや手元検証では内部ステージが手軽です。
一方、AWS上で本番運用するなら基本はS3外部ステージです。既にデータレイクや連携先がS3にあるケースが多く、Snowpipeによる自動取り込みやイベント連携(S3イベント通知)とも接続しやすいためです。外部ステージは CREATE STAGE ... URL='s3://bucket/path/' の形で作成し、認証は後述のストレージ統合に委ねます。1つのストレージ統合を複数の外部ステージが共有できるため、バケットやプレフィックスごとにステージを分けても認証設定は一元管理できます。
認証はストレージ統合(STORAGE INTEGRATION)を使い、S3のアクセスキーをSQLに直書きしないのが鉄則です。CREATE STORAGE INTEGRATION で STORAGE_AWS_ROLE_ARN にIAMロールのARNを指定し、STORAGE_ALLOWED_LOCATIONS で許可バケットを絞り込みます。Snowflake側はアカウントに紐づくIAMユーザー(DESCRIBE INTEGRATION で得られる STORAGE_AWS_IAM_USER_ARN)を自動生成し、そのユーザーが STORAGE_AWS_EXTERNAL_ID を条件にIAMロールをAssumeする信頼関係をS3側で組みます。キーの受け渡しが発生しないため、鍵ローテーションの運用負荷や漏洩リスクを構造的に減らせます。VPC内で通信を閉じたい要件があれば、AWS PrivateLink経由の非公開接続も選択肢になります。
STORAGE_ALLOWED_LOCATIONS を該当環境のバケットだけに限定しておくと、本番ステージから検証バケットを誤って読む事故を設定レベルで塞げます。IAMロールのポリシーも s3:GetObject と s3:ListBucket を必要なプレフィックスに絞るのが基本です。
03FILE FORMAT:読み方を一度定義して使い回す
FILE FORMATはファイルの解釈ルールです。CREATE FILE FORMAT で TYPE に CSV・JSON・AVRO・ORC・PARQUET・XML のいずれかを指定し、形式ごとのオプションを設定します。COPY INTOのインラインにも書けますが、名前付きFILE FORMATオブジェクトとして作成し使い回すのが実務では圧倒的に保守しやすい。区切り文字やヘッダ処理の定義が1箇所に集約され、複数テーブルのロードで挙動が揃うためです。
CSVでよく使うのは、ヘッダ行をスキップする SKIP_HEADER、囲み文字を扱う FIELD_OPTIONALLY_ENCLOSED_BY、空文字をNULLにする EMPTY_FIELD_AS_NULL、そして列数不一致を検知する ERROR_ON_COLUMN_COUNT_MISMATCH です。文字化け対策として ENCODING の明示、圧縮は既定の COMPRESSION = AUTO で拡張子から自動判定させるのが基本です。JSONやParquetのような半構造化データはいったんVARIANT列へ取り込み、後段でフラット化する構成が扱いやすくなります。
ERROR_ON_COLUMN_COUNT_MISMATCH = TRUE はデータ品質の番人です。上流が列を1本足した/減らしたといった変化を、黙って詰め替えずにロード時点で止めてくれます。検証環境では厳格に倒しておき、想定外のスキーマ変更を早期に顕在化させる運用が有効です。
04COPY INTOの実務:冪等性とロード履歴を味方にする
基本形は COPY INTO target_table FROM @my_stage FILE_FORMAT = (FORMAT_NAME = 'my_csv_ff') です。読み込む対象は FILES = ('a.csv','b.csv') で列挙するか、PATTERN = '.*2026-07.*[.]csv' のような正規表現で絞り込めます。列とファイル項目の対応を名前で自動マッピングしたい場合は MATCH_BY_COLUMN_NAME = CASE_INSENSITIVE が便利で、ParquetやJSONの取り込みで列順に依存しない堅牢なロードが組めます。
重要なのがロード履歴による冪等性です。COPY INTOはロード済みファイルを記録しており、同じステージへ同じCOPYを再実行しても、既にロード済みのファイルは自動的にスキップされます。この履歴は概ね64日間保持され、期間を超えた古いファイルはロード状態が不確実として扱われます。意図的に再ロードしたいときは FORCE = TRUE、逆にロード成功後にステージのファイルを自動削除したいときは PURGE = TRUE を使います。まず投入せず検証だけしたいなら VALIDATION_MODE = RETURN_ERRORS で本番ロード前にエラーを洗い出せます。
FORCE = TRUE で担保しようとすると、リトライのたびに二重ロードが起きます。冪等性はロード履歴に任せ、FORCE は「履歴を無視して敢えて入れ直す」明確な意図があるときだけに限定するのが安全です。パイプラインのリトライ設計とロード履歴の保持期間は、必ずセットで確認しておきましょう。
05ON_ERROR:エラーの握り方を用途で決める
ロード中にパースエラーや型不整合が出たとき、どう振る舞うかを決めるのが ON_ERROR です。選択肢は ABORT_STATEMENT(最初のエラーで全体を中止)、CONTINUE(エラー行を飛ばして継続)、SKIP_FILE(1件でもエラーがあればそのファイルを丸ごとスキップ)、しきい値付きの SKIP_FILE_<num> と SKIP_FILE_<num>% です。バルクのCOPY INTOでは既定が ABORT_STATEMENT、Snowpipeでは既定が SKIP_FILE である点は押さえておきましょう。
使い分けの指針は明確です。会計や在庫のように1行の欠損も許されないデータは ABORT_STATEMENT で止め、原因を直してから入れ直す。ログや行動履歴のように多少の欠損を許容してでも鮮度を優先したい場合は、SKIP_FILE_5% のようにしきい値を設けて「壊れたファイルだけ落とす」運用にする。いずれの場合も、どの行がなぜ弾かれたかを VALIDATE 関数や COPY_HISTORY で追跡できるようにしておくことが、後追い調査を成立させる前提になります。
06落とし穴:ファイルサイズを外すと「動くのに遅い・高い」
最後に、最もコストと性能に効くのに見落とされがちなのがファイルサイズです。COPY INTOはファイル単位で並列にロードするため、並列度の上限はファイル数に制約されます。Snowflakeが推奨するのは圧縮後でおおむね100〜250MB程度(あるいはそれ以上)のファイルに揃えること。ここを外すと、正しく動くのに非効率という厄介な状態になります。
私たちも小規模導入から大規模基盤まで複数業種で構築・運用してきましたが、この点は必ず検証段階で先に踏み抜いて確定させます。ある案件の検証環境では、数KB〜数MBの極小ファイルを毎分大量に生成する構成を試したところ、ファイルごとの固定オーバーヘッドが積み上がり、総データ量に対して不相応にロードが伸びました。逆に数十GB級の巨大単一ファイルは並列化の恩恵をまったく受けられず、しかもSnowflakeのガイドはおおむねGB級の非常に大きな単一ファイルを推奨しておらず、極端に長時間化した処理は中断・全件ロールバックのリスクも伴います。どちらも本番投入前の検証で顕在化させ、本番では上流の出力を分割・集約して最適サイズに寄せる設計に倒しました。
巨大ファイルしか手元にない場合は、Linux/macOSの split ユーティリティなどで行数ベースに分割してからステージへ置くと、素直に並列ロードが効きます。ポイントは「最適値を勘で決めない」こと。上流の出力頻度、1ファイルあたりの行数、圧縮率、ウェアハウスサイズは案件ごとに違うため、実データで数パターンを流し、ロード時間とクレジット消費を見て確定させるのが確実です。
07まとめ:3部品の設計判断を検証で固める
COPY INTOによるロードは、ステージ・FILE FORMAT・コピーオプションの3部品に分解して考えると設計判断が明快になります。AWS上ではS3外部ステージ+ストレージ統合でキーを持たない認証にし、FILE FORMATは名前付きで使い回して挙動を揃え、ON_ERRORは業務の許容度で握り方を決める。そして冪等性はロード履歴に任せ、FORCE は意図的な再投入だけに限る。最後にファイルサイズ——圧縮後100〜250MB前後という一点を検証で確定させておくだけで、動くのに遅い・高い・落ちるという典型的な失敗の大半は本番前に潰せます。仕様の細部は必ず一次情報で裏を取り、実データで数字を測って決めることを強くおすすめします。
参考情報(一次情報)
- COPY INTO <table> | Snowflake Documentation
- Preparing your data files | Snowflake Documentation
- CREATE FILE FORMAT | Snowflake Documentation
- CREATE STAGE | Snowflake Documentation
- Option 1: Configure a Snowflake storage integration to access Amazon S3 | Snowflake Documentation
- CREATE STORAGE INTEGRATION | Snowflake Documentation
AWS×SnowflakeのデータロードやCOPY INTO設計でお困りなら、S3連携から最適ファイルサイズの検証までEMWがご支援します。お気軽にご相談ください。
相談する