dbt Cloud で freshness を試してみた

dbt Cloud で freshness を試してみた

2025.09.18

はじめに

dbt Cloud で freshness について特にタイムゾーンの扱いを整理しておきたく記事としました。
過去にもこちらの機能に関する記事はありますので、あわせてご参照ください。

https://dev.classmethod.jp/articles/dbt-sources/

機能の概要

本機能については、以下に記載があります。

https://docs.getdbt.com/reference/resource-properties/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
  • タイムスタンプ

事前準備

検証用に以下の内容でテーブルを定義します。

			
			-- タイムゾーンを確認
>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を使用するテーブルカラムではテストを通過しています。

image

この際、ログで確認できたクエリは以下の通りです。参考までに、鮮度テスト後、このクエリを手動実行したタイミングの結果を載せています。

			
			--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分以上経過後の結果は下図の通りです。

image 1

NTZ のテーブルは依然としてテストに通過しています。ドキュメントでは UTC に変換することが推奨されているので、以下のように変換するクエリを追加しテストします。

			
			loaded_at_field: "convert_timezone('UTC', timestamp_val)"

		

この場合、全てエラーとなりました。

image 2

この際のログに表示されるクエリは以下のようになっており、デバッグ実行もこのままできる形と思います。

			
			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');

		

この状態でテストを実行すると想定通り警告となりました。

image 3

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 について整理しました。特にタイムゾーンの扱いは注意が必要と思いました。
こちらの内容が何かの参考になれば幸いです。

参考

https://www.getgalaxy.io/learn/glossary/dbt-source-freshness

この記事をシェアする

FacebookHatena blogX

関連記事