
dbt Cloud で freshness を試してみた
はじめに
dbt Cloud で freshness について特にタイムゾーンの扱いを整理しておきたく記事としました。
過去にもこちらの機能に関する記事はありますので、あわせてご参照ください。
機能の概要
本機能については、以下に記載があります。
dbt は DWH 上のデータ変換に特化しているため、定期的に変換処理を実行するとしてもデータが更新されていなければ意味がありません。このために使用できる機能として、sources
に定義しているテーブルのデータの鮮度をチェックすることが可能です。
loaded_at_field
の使用- 鮮度テストの一般的な方法は、ソーステーブル内の既存のタイムスタンプ列を参照することになります。
loaded_at_field
プロパティに列名を指定すると、max([指定された列名])
というロジックで最新のタイムスタンプを取得し、テスト実行時の日時と比較されます - 特定のレコードを比較対象とするような
filter
の追加も可能です
- 鮮度テストの一般的な方法は、ソーステーブル内の既存のタイムスタンプ列を参照することになります。
loaded_at_query
の使用- テーブルに適切なタイムスタンプ列がない場合や、より複雑なロジックで最終更新日時を定義したい場合は、
loaded_at_query
プロパティを使用できます。これにより、カスタムSQL クエリでテストに使用するタイムスタンプを生成できます - 以下は公式ドキュメントからの引用ですが、「過去7日間のうち、少なくとも2,000件のレコードが正常に処理された最新の日付」のタイムスタンプを特定し、その日時とテスト実行時を比較しています
- テーブルに適切なタイムスタンプ列がない場合や、より複雑なロジックで最終更新日時を定義したい場合は、
sources:
- name: your_source
config:
freshness: # changed to config in v1.9
error_after:
count: 2
period: hour
loaded_at_query: |
select max(_sdc_batched_at) from (
select * from {{ this }}
where _sdc_batched_at > dateadd(day, -7, current_date)
qualify count(*) over (partition by _sdc_batched_at::date) > 2000
)
タイムゾーンの考慮
また、こちらに記載があるように鮮度テストで使用するタイムスタンプ列には、UTC(協定世界時)を使用することが推奨されています。
試してみる
前提条件
- DWH:Snowflake
- タイムスタンプ
- Snowflake では3種類のタイムスタンプをサポートしているので各データ型で試してみます
事前準備
検証用に以下の内容でテーブルを定義します。
-- タイムゾーンを確認
>SHOW PARAMETERS LIKE 'TIMEZONE' IN ACCOUNT;
+----------+------------+---------------------+---------+-------------+--------+
| key | value | default | level | description | type |
|----------+------------+---------------------+---------+-------------+--------|
| TIMEZONE | Asia/Tokyo | America/Los_Angeles | ACCOUNT | time zone | STRING |
+----------+------------+---------------------+---------+-------------+--------+
-- TIMESTAMP_NTZ用のテーブルを作成し、データを挿入
CREATE OR REPLACE TABLE timestamp_ntz_table (
timestamp_val TIMESTAMP_NTZ
);
INSERT INTO timestamp_ntz_table (timestamp_val)
VALUES (CURRENT_TIMESTAMP());
-- TIMESTAMP_LTZ用のテーブルを作成し、データを挿入
CREATE OR REPLACE TABLE timestamp_ltz_table (
timestamp_val TIMESTAMP_LTZ
);
INSERT INTO timestamp_ltz_table (timestamp_val)
VALUES (CURRENT_TIMESTAMP());
-- TIMESTAMP_TZ用のテーブルを作成し、データを挿入
CREATE OR REPLACE TABLE timestamp_tz_table (
timestamp_val TIMESTAMP_TZ
);
INSERT INTO timestamp_tz_table (timestamp_val)
VALUES (CURRENT_TIMESTAMP());
--ntz_table
>SELECT
*
--timestamp_valには現在のセッションのタイムゾーンが使用される
,convert_timezone('UTC', timestamp_val)
FROM timestamp_ntz_table;
+-------------------------+----------------------------------------+
| TIMESTAMP_VAL | CONVERT_TIMEZONE('UTC', TIMESTAMP_VAL) |
|-------------------------+----------------------------------------|
| 2025-09-18 15:25:55.291 | 2025-09-18 06:25:55.291 +0000 |
+-------------------------+----------------------------------------+
--ltz_table
>SELECT
*,
convert_timezone('UTC', timestamp_val)
FROM timestamp_ltz_table;
+-------------------------------+----------------------------------------+
| TIMESTAMP_VAL | CONVERT_TIMEZONE('UTC', TIMESTAMP_VAL) |
|-------------------------------+----------------------------------------|
| 2025-09-18 15:25:56.563 +0900 | 2025-09-18 06:25:56.563 +0000 |
+-------------------------------+----------------------------------------+
--tz_table
>SELECT
*
,convert_timezone('UTC', timestamp_val)
FROM timestamp_tz_table;
+-------------------------------+----------------------------------------+
| TIMESTAMP_VAL | CONVERT_TIMEZONE('UTC', TIMESTAMP_VAL) |
|-------------------------------+----------------------------------------|
| 2025-09-18 15:25:58.020 +0900 | 2025-09-18 06:25:58.020 +0000 |
+-------------------------------+----------------------------------------+
ソースと鮮度テストを定義
以下の内容で、各カラムに対して鮮度テストを定義しました。
version: 2
sources:
- name: test_public
database: TEST_DB
schema: PUBLIC
tables:
- name: timestamp_ntz_table
config:
freshness:
warn_after:
count: 12
period: minute
error_after:
count: 24
period: minute
loaded_at_field: timestamp_val
- name: timestamp_ltz_table
config:
freshness:
warn_after:
count: 12
period: minute
error_after:
count: 24
period: minute
loaded_at_field: timestamp_val
- name: timestamp_tz_table
config:
freshness:
warn_after:
count: 12
period: minute
error_after:
count: 24
period: minute
loaded_at_field: timestamp_val
この設定後、dbt source freshness
コマンドを06:38:04(UTC)に実行した場合、下図のようになりました。テーブル定義から12分以上経過しているので、警告となりますが、NTZを使用するテーブルカラムではテストを通過しています。
この際、ログで確認できたクエリは以下の通りです。参考までに、鮮度テスト後、このクエリを手動実行したタイミングの結果を載せています。
--ntz
select
max(timestamp_val) as max_loaded_at,
convert_timezone('UTC', current_timestamp()) as snapshotted_at
from TEST_DB.PUBLIC.timestamp_ntz_table;
+-------------------------+-------------------------------+
| MAX_LOADED_AT | SNAPSHOTTED_AT |
|-------------------------+-------------------------------|
| 2025-09-18 15:25:55.291 | 2025-09-18 06:39:29.619 +0000 |
+-------------------------+-------------------------------+
--ltz
select
max(timestamp_val) as max_loaded_at,
convert_timezone('UTC', current_timestamp()) as snapshotted_at
from TEST_DB.PUBLIC.timestamp_ltz_table;
+-------------------------------+-------------------------------+
| MAX_LOADED_AT | SNAPSHOTTED_AT |
|-------------------------------+-------------------------------|
| 2025-09-18 15:25:56.563 +0900 | 2025-09-18 06:40:46.153 +0000 |
+-------------------------------+-------------------------------+
--tz
select
max(timestamp_val) as max_loaded_at,
convert_timezone('UTC', current_timestamp()) as snapshotted_at
from TEST_DB.PUBLIC.timestamp_ltz_table;
+-------------------------------+-------------------------------+
| MAX_LOADED_AT | SNAPSHOTTED_AT |
|-------------------------------+-------------------------------|
| 2025-09-18 15:25:56.563 +0900 | 2025-09-18 06:41:38.819 +0000 |
+-------------------------------+-------------------------------+
テーブル定義から24分以上経過後の結果は下図の通りです。
NTZ のテーブルは依然としてテストに通過しています。ドキュメントでは UTC に変換することが推奨されているので、以下のように変換するクエリを追加しテストします。
loaded_at_field: "convert_timezone('UTC', timestamp_val)"
この場合、全てエラーとなりました。
この際のログに表示されるクエリは以下のようになっており、デバッグ実行もこのままできる形と思います。
select
max(convert_timezone('UTC', timestamp_val)) as max_loaded_at,
convert_timezone('UTC', current_timestamp()) as snapshotted_at
from TEST_DB.PUBLIC.timestamp_tz_table;
また、TIMESTAMP_NTZ
についてconvert_timezone
関数を使用しない状態で、手動で UTC においても警告となるタイムスタンプのレコードを追加してみます。
※上記と実行タイミングが異なります
CREATE OR REPLACE TABLE timestamp_ntz_table (
timestamp_val TIMESTAMP_NTZ
);
INSERT INTO timestamp_ntz_table (timestamp_val)
VALUES ('2025-09-18 08:00:00.000');
この状態でテストを実行すると想定通り警告となりました。
TIMESTAMP_NTZ
カラムを鮮度テストで使用する場合、dbt はloaded_at_field
で指定されたNTZ
(タイムゾーン情報なし)の値をそのまま使用するようです。
そして、この値は、テスト実行時のUTC 時間と比較されます。
NTZ
カラムに格納された時刻と UTC との間に時間差があれば、その分だけ実際の鮮度テストにズレが生じることとなるため、TIMESTAMP_NTZ
のカラムに対する鮮度テストが必要な場合は注意する必要があります。
スキーマレベルでまとめてテストを定義
特定のスキーマ配下のテーブルが、共通のタイムスタンプ カラム名を持つような場合は、以下のようにまとめて設定が可能です。
この場合、各テーブルは共通のカラム名を持つ必要があるので、鮮度テストをスキップしたいテーブルがある場合は、最後のtest
テーブルのように設定すればよいです。その他、特定のテーブルは全体の設定を上書きすることも可能です。
version: 2
sources:
- name: test_public
database: TEST_DB
schema: PUBLIC
config:
freshness:
warn_after:
count: 12
period: minute
error_after:
count: 24
period: minute
loaded_at_field: "convert_timezone('UTC', timestamp_val)"
tables:
- name: timestamp_ntz_table
- name: timestamp_ltz_table
- name: timestamp_tz_table
- name: test
config:
freshness: # このテーブルには鮮度テストを行わない
さいごに
dbt Cloud で freshness について整理しました。特にタイムゾーンの扱いは注意が必要と思いました。
こちらの内容が何かの参考になれば幸いです。
参考