ふくふくHukuhuku Inc.
EP.10dbt 10分公開: 2026-05-10

seeds と snapshots:静的データと SCD Type 2

seeds は CSV を DWH にロードする仕組み (国コード等の小規模マスタに最適)。snapshots は変更履歴を残す SCD Type 2 を 1 設定で実現する強力機能。両者の使い分けと落とし穴。

#dbt#seeds#snapshots#SCD
シェア

には model 以外に seeds ( ロード) と snapshots (履歴保存) という機能があります。それぞれ用途が明確で、知っておくと「model 化するべきか seed か」「変更履歴をどう残すか」の判断が楽になります。

seeds:CSV を にロード

seeds/country_codes.csv
Code
code,name_ja,name_en,regionJP,日本,Japan,asiaUS,アメリカ合衆国,United States,north_americaGB,イギリス,United Kingdom,europeDE,ドイツ,Germany,europe
ロード
Bash
dbt seed                          # 全 seed を再ロード (デフォルト truncate+insert)dbt seed --select country_codes   # 特定だけdbt seed --full-refresh           # スキーマ含めて作り直し
seeds の config (dbt_project.yml)
YAML
seeds:  analytics:    country_codes:      +column_types:        code: varchar(2)        name_ja: varchar(100)        name_en: varchar(100)        region: varchar(50)    industry_codes:      +schema: reference   # 別スキーマに分離
seed の限界

seed は数千行までが現実解。10 万行を超えると `dbt seed` が遅くなり、 でも diff が読めない。大規模マスタは で取り込んで通常 model にすべき。

seed が向くケース

  • 国コード・通貨マスタ: 数百行、めったに変わらない
  • 業界コードのマッピング: NACE / GICS 等の固定マスタ
  • 祝日カレンダー: 数年分の固定リスト
  • 勘定科目マスタ: 中小企業なら数十〜数百行
  • 設定値: しきい値、許可フラグ等の小規模ルックアップ

snapshots:SCD Type 2 を 1 設定で

SCD Type 2 = 「過去の状態を行として残しつつ、現在の状態も識別できる」スキーマ設計。dbt の snapshot はこれを 1 設定で実現します。

snapshots/customers_snapshot.sql
SQL
{% snapshot customers_snapshot %}
  {{    config(      target_schema='snapshots',      unique_key='customer_id',      strategy='check',          -- 'check' or 'timestamp'      check_cols=['email', 'phone', 'tier', 'address'],      invalidate_hard_deletes=True    )  }}
  SELECT * FROM {{ source('app', 'customers') }}
{% endsnapshot %}
実行
Bash
dbt snapshot   # 通常は 1 日 1 回 (cron で)# → snapshots.customers_snapshot に変化があった行が追記される

snapshot が出力するカラム

カラム意味
`dbt_scd_id`snapshot 行の一意 ID
`dbt_updated_at`この行が記録された時刻
`dbt_valid_from`この状態が有効になった時刻
`dbt_valid_to`この状態が終わった時刻 (現在も有効なら NULL)
元テーブルの全カラムそのまま
snapshot を活用するクエリ例
SQL
-- ある時点での顧客状態を取得SELECT *FROM {{ ref('customers_snapshot') }}WHERE customer_id = 'C001'  AND '2027-06-01 00:00:00' BETWEEN dbt_valid_from AND COALESCE(dbt_valid_to, CURRENT_TIMESTAMP());
-- 顧客プラン変更の履歴SELECT  customer_id,  tier,  dbt_valid_from,  dbt_valid_toFROM {{ ref('customers_snapshot') }}WHERE customer_id = 'C001'ORDER BY dbt_valid_from;

戦略の選択:check vs timestamp

戦略判定方法向く場面
timestampソースの updated_at が変わったら新行ソースに信頼できる updated_at がある場合
check指定カラムの値が変わったら新行updated_at がない / 信頼できない場合

snapshot の落とし穴

削除検出は invalidate_hard_deletes

ソーステーブルから行が 削除された場合、デフォルトでは検知されない。`invalidate_hard_deletes: True` を設定すると、消えた行に `dbt_valid_to` を入れて「終了」扱いにする。ハード削除がある業務テーブルには必須。

snapshot の頻度

`dbt snapshot` を実行した瞬間の状態が記録される。1 時間に 1 回なら 1 時間内の変化は捨てられる。取りたい粒度に応じて頻度を決める (通常は 1 日 1 回 〜 1 時間 1 回)。

snapshot は元に戻せない

snapshot テーブルは 削除も full-refresh も基本しない(過去履歴が消える)。snapshot 戦略を変えるときは新 snapshot を立てるのが正解。

次の話

EP.11 では incremental model の差分更新パターンを深掘りする予定です(近日公開)。

シェア

この記事の感想を教えてください

あなたの 1 クリックで、本当にこの記事は更新されます。「もっと詳しく」「続編希望」が一定数集まった記事は、 ふくふくが 実際に内容を拡充したり続編記事を公開 します。 送信したリアクションはお使いのブラウザに記録され、再カウントされません。

シリーズの外も探す:

まずは、現状を聞かせてください。

要件が固まっていなくて大丈夫です。現状診断と方針提案までを無料でお手伝いします。

無料相談フォームへ hello [at] hukuhuku [dot] co [dot] jp