【dbt Docs】Building a dbt Project - Snapshots
Snapshots
Related documentation
-
-
resource-path
-
target_schema
-
target_database
-
unique_key
-
strategy
-
updated_at
-
check_cols
-
dbt_project.ymlの
snapshots:
-
.sql
config ブロック -
.yml
の resource property
snapshots/postgres_app/orders_snapshot.sql{% snapshot orders_snapshot %} {{ config( unique_key='id', strategy='timestamp', updated_at='updated_at' ) }} -- Pro-Tip: Use sources in snapshots! select * from {{ source('jaffle_shop', 'orders') }} {% endsnapshot %}
-
-
-
snapshots/
ディレクトリ、snapshot-paths
で設定も可能 models/
-
-
$ dbt snapshot --help
Getting started(はじめに)
What are snapshots?( snapshotsとは)
分析者はデータの中身が変更するテーブルを、以前のある時点にさかのぼって確認したい場合が多々ある。データソース側で過去のある時点のデータを見れるようにしている場合もあるけど、そうでない場合も多い。dbtはsnapshotという機能を提供している。これは変更内容を記録しておく機構
Snapshots機能は、type-2 Slowly Changeing Dimensions(SCDs)
を元に実装されている。
下記のような変更を記録する( dbt_valid_from, dbt_valid_to )
id | status | updated_at |
---|---|---|
1 | pending | 2019-01-01 |
id | status | updated_at |
---|---|---|
1 | shipped | 2019-01-02 |
id | status | updated_at | dbt_valid_from | dbt_valid_to |
---|---|---|---|---|
1 | pending | 2019-01-01 | 2019-01-01 | 2019-01-02 |
2 | shipped | 2019-01-02 | 2019-01-02 | null |
dbtでは、 snapshots
は、select
句で記載される。snapshots/
に配置される.sql
に置かれる場合が多い。
{% snapshot orders_snapshot %}
{{
config(
target_database='analytics',
target_schema='snapshots',
unique_key='id',
strategy='timestamp',
updated_at='updated_at',
)
}}
select * from {{ source('jaffle_shop', 'orders') }}
{% endsnapshot %}
dbt snapshot
実行時の挙動としては
-
最初の起動時 まずスナップショットテーブルを作成する。(
select
句の実行そのまま )dbt_valid_from
とdbt_valid_to
が追加される。dbt_valid_to = null
がまず入る -
以降の実行時 変更されたレコードと新規レコードをチェックする。
- 変更された場合は、
dbt_valid_to
も更新される - 新しいレコードが入った場合は、挿入される。
dbt_valid_to = null
となる
- 変更された場合は、
Example
プロジェクトにスナップショットを追加するためには
-
snapshots
ディレクトリに、.sql
ファイルを作成する 例)snapshots/orders.sql
- blockに snapshotの定義を記載するsnapshots/orders.sql
{% snapshot orders_snapshot %} ... {% endsnapshot %}
-
select
句を記載するsnapshots/orders.sql{% snapshot orders_snapshot %} select * from {{ source('jaffle_shop', 'orders') }} {% endsnapshot %}
- クエリの結果セットに、レコードが最後に更新された日時を示す信頼できるタイムスタンプ列が含まれているかどうかを確認します。 この例の場合、
updated_at
を見れば更新の判断はできるので、timestamp
を使っての判断ができる。updated_at
などtimestampがない場合は、check
を使って判断をすることができる。 - blockを使用して設定をすることもできる。(個別の
.sql
ファイルでも,dbt_project.yml
でも)snapshots/orders.sql{% snapshot orders_snapshot %} {{ config( target_database='analytics', target_schema='snapshots', unique_key='id', strategy='timestamp', updated_at='updated_at', ) }} select * from {{ source('jaffle_shop', 'orders') }} {% endsnapshot %}
-
dbt snapshot
コマンドを実行する。この例では、
analytics.snapshots.orders_snapshot
テーブルが作成される。 - 作成されたテーブルを確認する
- 念の為
dbt snapshot
を実行して、変更追加が反映されるか確認する -
ref
関数で、他のモデルから参照することができるmodels/changed_orders.sqlselect * from {{ ref('orders_snapshot') }}
-
dbt snapshot
コマンドを定期実行する。( cronとかで ) snapshotは、定期的に頻繁に実行すると役に立つ。
Detecting row changes
データがどう変更されたか?をチェックする方法が2種類用意されている。 timestamp
とcheck
Timestamp strategy (recommended)
(タイムスタンプ戦略:おすすめ)
更新日時のカラムを元に判断する。updated_at
{% snapshot orders_snapshot_timestamp %}
{{
config(
target_schema='snapshots',
strategy='timestamp',
unique_key='id',
updated_at='updated_at',
)
}}
select * from {{ source('jaffle_shop', 'orders') }}
{% endsnapshot %}
Check strategy
更新日時といったカラムがない場合に、こちらを使う。指定のカラムが過去と変更があるかないか?を比較することで機能する。
構成 | 説明 | 例 |
---|---|---|
check_cols |
all 全部のカラム変更を確認する、またはすべての列を確認する列のリスト |
["name", "email"] |
{% snapshot orders_snapshot_check %}
{{
config(
target_schema='snapshots',
strategy='check',
unique_key='id',
check_cols=['status', 'is_cancelled'],
)
}}
select * from {{ source('jaffle_shop', 'orders') }}
{% endsnapshot %}
Hard deletes (opt-in)
ソースクエリから削除された行は、デフォルトでは無効化されない。
invalidate_hard_deletes
を使えば追跡可能。
Configuring snapshots
Snapshot configurations
- target_database
- target_schema
- stragegy
timesatamp
orcheck
- unique_key
- check_cols :
check
の際に判断対象となるカラム名のリスト - updated_at :
timestamp
の際に判斷対象となるtimestamp列名 - invalidate_hard_deletes : ソースデータのカラム削除に追従するか
Configuration best practices (構成のベストプラクティス)
- strategy :
timestamp
を使う -
unique_key
が本当にユニーク化確認する - 分析用のスキーマとは別のスキーマを指定する
- スナップショットは再構成ができないので、権限的にも簡単に削除や変更ができないように権限設定をしておくほうが良い
Snapshot query best practices
- ソースデータのスナップショットを取る
-
source
関数を使う。直書きしない、リネージュを追えるようにも - できるだけ多くの列を含む。実際パフォーマンスが許すなら
select *
を使うことを推奨 - スナップショットではJOINは使わない
- 変換は極力行わない(ソースデータだけ取ろうね) ビジネスロジックは変更になりやすいので
Snapshot meta-fields
- dbt_valid_from 最初の挿入時のタイムスタンプ
- dbt_valid_to 無効になった時のタイムスタンプ
- dbt_scd_id 生成された一意キー、dbt内部で使う
- dbt_updated_at 行が挿入された時のソースレコードの
updated_at
、dbt内部で使う
FAQs
-
一度に1つのスナップショットを実行するにはどうすればよいですか?
$ dbt snapshot --select order_snapshot
-
スナップショットコマンドを実行する頻度はどれくらいですか?
1時間毎、1日毎 などに取ることを推奨。それ以下の場合は別の手段を検討してください。
-
スナップショットクエリに新しい列を追加するとどうなりますか?
追加カラムは追加される。ただ、削除カラムはデフォルトでは削除しない
-
フックはスナップショットで実行されますか?
pre-hook, post-hook, on-run-start, on-ran-endで使用できる。
-
スナップショット用の`target_schema`が1つしかないのはなぜですか?
-
プロジェクトの`snapshot`ディレクトリ以外のディレクトリにスナップショットを保存できますか?
デフォルトでは
snapshots/
ディレクトリ。snapshot-paths
で設定することも可能
Discussion