Snowflakeでデータ基盤を運用していると、「Snowflake内で増分処理を組みたい」場面が頻繁に出てきます。外部からのCDCではなく、Snowflake内のテーブル変更を追跡して下流テーブルに反映する、というニーズです。これを担うのがSnowflake StreamsとTasksの組み合わせです。

Streamsは「テーブルの変更を追跡するメタデータビュー」、Tasksは「スケジュール実行の仕組み」。両者を組み合わせると、Snowflake内で完結する増分パイプラインが組めます。実装パターンを整理します。

Streamsの基本動作

Streamsは「最後にチェックポイントしてから変わったレコード」を返すビューです。読み出すたびに、変更履歴がオフセットされます。

-- Streamの作成
CREATE STREAM stream_orders ON TABLE silver.orders;

-- 変更を取得
SELECT * FROM stream_orders;

-- 取得した結果に対して操作(INSERT/MERGE/UPDATE)を行うと
-- 自動的にチェックポイントが進む

Streamの結果には`METADATA$ACTION`(INSERT/UPDATE/DELETE)、`METADATA$ISUPDATE`(更新かどうか)、`METADATA$ROW_ID`が追加されます。これらを使って下流の更新ロジックを組みます。

Standard vs Append-only Stream

タイプ追跡対象用途
Standard StreamINSERT・UPDATE・DELETE更新も削除も反映したい
Append-only StreamINSERTのみイベントログのように追加だけ
Insert-only Stream(External Tables用)INSERT検知外部テーブル用

Append-onlyの方が軽量で性能が良いので、「追加だけ」と分かっているテーブルではこれを選びます。

Tasksとの組み合わせ

-- Streamの変更を定期的に処理するTask
CREATE TASK task_sync_orders
  WAREHOUSE = WH_TRANSFORM
  SCHEDULE = '5 MINUTE'
  WHEN SYSTEM$STREAM_HAS_DATA('stream_orders')
AS
  MERGE INTO gold.fct_orders t
  USING (
    SELECT * FROM stream_orders
    WHERE METADATA$ACTION != 'DELETE'
  ) s
  ON t.order_id = s.order_id
  WHEN MATCHED THEN UPDATE SET ...
  WHEN NOT MATCHED THEN INSERT ...;

-- Taskを起動
ALTER TASK task_sync_orders RESUME;

`WHEN SYSTEM$STREAM_HAS_DATA(…)`で「変更があるときだけ実行」できるので、空処理を避けてコストを抑えられます。Snowflakeのウェアハウスの考え方はSnowflakeとはを参照してください。

dbt incrementalとの使い分け

Streams + Tasksdbt incremental
変更追跡Snowflake内部クエリで判定(updated_at等)
遅延1分〜スケジュール頻度に依存
削除の検知標準でサポート「削除フラグ」設計が必要
運用ツールSnowflakeのDDLdbtプロジェクト
テスト・ドキュメント別途dbtで統合

「dbtプロジェクトで一元管理」ならincremental、「リアルタイム要件・削除検知」ならStreams、と分かれます。多くの組織でdbt incrementalから始め、ニーズが出てきたらStreamsを部分的に使う、という併用が現実的です。dbtの基本はincremental models設計を参照してください。

運用上のハマりどころ

  • Stream保持期間:Streamの変更は標準で14日間保持。それより前にTaskが動かないとデータが失われる。重要な処理はTaskの正常稼働を監視。
  • Stream Consumerは1つ:1つのStreamを複数のTaskが読むと、片方しかチェックポイントが進まない。複数下流が必要ならStreamを複数作る。
  • 大きなテーブルへのStream作成:既存の大規模テーブルにStreamを張ると、初回コストが大きい。導入時のテーブル運用に注意。
  • Taskのコスト管理:頻繁にTaskを動かすとウェアハウスのクレジットが嵩む。`STREAM_HAS_DATA`で無駄な起動を抑える。

典型的な利用パターン

  • BronzeからSilverへの増分反映:Streamで変更検知、MERGEで反映
  • SilverからGoldの集計表更新:Streamで変更検知、集計テーブルを増分更新
  • 監査ログの自動構築:Streamで全変更を記録、別テーブルに追記
  • 外部システムへの通知:Streamで変更検知、外部関数でSNS/API呼び出し

まとめ

  • Streamsはテーブル変更を追跡するメタデータビュー、Tasksはスケジュール実行。
  • 組み合わせでSnowflake内完結のCDCパイプラインが組める。
  • Standard / Append-onlyの2タイプで、用途に応じて選ぶ。
  • dbt incrementalとは「内部追跡 vs クエリ判定」で使い分け。
  • 保持期間14日、1Stream=1Consumer、大規模テーブル初回コスト等が運用注意点。

全体像はCDC実装ガイド、隣接はDebezium とはPostgreSQL論理レプリケーション。Snowflake内CDC設計の壁打ちは、DE-STKの初回相談(30分・無料)もご利用ください。

よくある質問(FAQ)

Q. Dynamic Tablesとどう違いますか?

A. Dynamic TablesはSnowflakeの新機能で、「SQLで定義した結果テーブルが自動的に最新に保たれる」マテリアライズドビュー的な機能です。StreamsとTasksを使う代わりに、Dynamic Tablesで宣言的にパイプラインを書く選択肢が増えています。Streams+Tasksは「自分で更新ロジックを書く」のに対し、Dynamic Tablesは「Snowflakeが自動で最適化」します。と棲み分けます。

Q. dbtからStreamsを使えますか?

A. dbtの`pre_hook`/`post_hook`でStreamのCRUDを操作できますが、dbtプロジェクトのモデル管理とStreamsの状態管理が分かれることに注意が必要です。dbtコミュニティ製のパッケージも存在しますが、多くの組織は「dbt incremental+必要に応じてStreamsを別運用」のハイブリッドにしています。

Q. Streamの保持期間14日を伸ばせますか?

A. デフォルト14日は、ソーステーブルの`DATA_RETENTION_TIME_IN_DAYS`に依存します。これを伸ばすと、Streamの保持期間も伸びます。ただしストレージコストが増えるので、業務要件で必要な期間に絞ります。「Taskが3日止まっても大丈夫」なら7日設定、というように設計します。

Q. Snowflake外部にイベントを流したい場合は?

A. External Functions(AWS Lambda・Azure Functions経由)でAPI呼び出し、Snowflake Stream → External StageへのCOPYでファイル経由配信、などの方法があります。本格的なイベント駆動アーキテクチャを組むなら、Kafkaを別に立ててDebezium+Kafkaで構成する方が素直です。

▼ このトピックをポチポチ学ぶ

ストリーミングとCDC

関連記事を順序立てて読みながら、ステップごとに4択クイズで理解を確認できる学習パスです。登録不要・進捗自動保存。

学習パスを始める →