pre-hook / post-hookは、各ノード(モデル・スナップショット・シードなど)の実行直前/直後にSQLやマクロを差し込めるdbtの仕組みです。権限付与、監査ログ、統計再計算などの自動化に有効です。
本稿は公式ドキュメントに基づく安定した挙動を前提に、実務で安全に使うための注意点と、Analytics Engineer試験で問われやすい比較観点を整理します。
pre-hookは対象ノードの実行直前、post-hookは実行直後に評価・実行されます。hookの内容はJinjaでテンプレート化でき、this、target、var、env_varなどのコンテキストを参照可能です。
これらはノード単位で動作するフックであり、プロジェクト全体の開始/終了時に一度だけ動作するon-run-start / on-run-endとは用途が異なります。
dbt run全体では、on-run-startが最初に一度だけ実行された後、各ノードについてpre-hook → 本体SQL → post-hookの順に進み、最後にon-run-endが一度だけ実行されます。
多くのアダプタではノードの本体SQLとpre/post hookは同一トランザクション内で実行されます。設定でtransaction: false(サポートされるアダプタのみ)を指定すると、フックを独立トランザクションとして実行可能です。DML/DDLの自動コミット挙動はウェアハウス依存のため、権限付与やセッション設定などは必要に応じて分離するのが安全です。
dbt実行ライフサイクルとフックの位置づけ
post-hookは新規作成・置換直後のリレーションに対する権限付与や統計再計算に適しています。pre-hookは実行前に必要な下準備(ステージングや一時テーブルのクリーニング)に向いています。
セッションやクエリ単位の設定は、フックだけでなくsql_headerやアダプタ固有の設定(例: Snowflakeのquery_tag)を併用すると安定します。
フックはdbt_project.ymlでモデル階層に一括適用するか、個別のモデル内config()で指定できます。リストで複数記述し、上から順に実行されます。マクロ呼び出しも可能です。
アダプタが対応する場合、transaction: falseでフックを独立トランザクション化できます。権限付与やロギングなど、失敗時に本体のロールバックへ巻き込みたくない処理で有効です。
設定例(dbt_project.yml、モデル内config、マクロ)
# dbt_project.yml(抜粋)
models:
my_project:
+post-hook:
- sql: grant select on {{ this }} to role ANALYST
transaction: false
- "{{ log('built ' ~ this, info=True) }}"
# models/fct_orders.sql(モデル個別のフック)
{{ config(
materialized='table',
pre_hook=[
"delete from {{ ref('load_control') }} where model='{{ this.identifier }}'"
],
post_hook=[
"{{ insert_audit_record(this, 'fct_orders') }}"
]
) }}
select *
from {{ ref('stg_orders') }}
# macros/insert_audit_record.sql(監査ログ用マクロ)
{% macro insert_audit_record(relation, model_name) %}
{% if execute %}
insert into {{ ref('audit_log') }}(model, relation, executed_at, environment)
values ('{{ model_name }}', '{{ relation }}', current_timestamp, '{{ target.name }}');
{% endif %}
{% endmacro %}Analytics Engineer試験では、フックの適用粒度、実行タイミング、トランザクション境界の違いが典型論点です。どのユースケースにどのフックを選ぶべきかを即答できるようにしておきましょう。
特に、プロジェクト開始/終了で一度だけ記録したい監査はon-run-start/end、各モデルに付与が必要な権限はpost-hook、前処理のクリーンアップはpre-hookという棲み分けを覚えるのが効果的です。
| フック種別 | タイミング/粒度 | トランザクション | 主な用途 |
|---|---|---|---|
| pre-hook | 各ノード実行の直前 | 通常は本体SQLと同一。必要に応じて分離可(adapter依存) | 一時テーブル準備、クリーンアップ、セッション前提条件の設定 |
| post-hook | 各ノード実行の直後 | 通常は本体SQLと同一。分離で権限付与等を安全化 | GRANT、監査ログ、統計再計算 |
| on-run-start / end | ラン開始時/終了時に1回 | 単独で実行(ノードと独立) | ラン全体の監査記録、環境初期化/後片付け |
フックは便利な一方で、トランザクション境界や順序の取り扱いを誤ると意図しない副作用を招きます。以下を守ると安定します。
Analytics Engineer
問題 1
あるチームは、dbt runの開始時に監査テーブルへ1行だけ実行ログを入れ、各モデルが作成・更新された直後に必ず権限を付与したい。最も適切な構成はどれか。
正解: A
監査テーブルへラン単位で1行だけ挿入するのはon-run-startが適切。モデル作成直後の権限付与は各ノードに対するpost-hookが適切。pre-hookは本体実行前の前処理であり、GRANTは作成後のリレーションに行う方が自然です。
エフェメラルモデルにpre/post hookは効きますか?
効きません。エフェメラルは実体のリレーションを作らないため、pre/post hookの対象外です。権限付与などは下流の物理リレーション側で行ってください。
トランザクションの挙動はどうなりますか?フックが失敗した場合は?
多くのアダプタではpre/post hookは本体SQLと同一トランザクションで実行され、pre-hook失敗で本体は実行されません。post-hook失敗はノード失敗となりますが、リレーションは既に作成・更新済みの可能性があります。DDLの自動コミットなどアダプタ依存の例外があるため、必要に応じてtransaction: falseで分離し、SQLは冪等化してください。
フックのデバッグや動作確認はどう行うべきですか?
dbt compileで生成SQLを確認し、--debugでログ詳細を見る方法が基本です。マクロ主体のフックはdbt run-operationで単体実行・検証が可能です。log()マクロで実行時情報を出力して確認するのも有効です。
NicheeLab編集部
データエンジニアリング・クラウド資格の専門家。Databricks・Snowflake等の認定資格を保有し、実務経験に基づいた問題作成・解説を行っています。NicheeLab運営。
dbt Model の基礎: SQL で定義する変換の最小単位
Analytics Engineer 向けに、dbt Model の定義、マテリアライゼーション、依存関係、インクリメン...
dbt Analytics Engineer 試験ガイド: 出題範囲・配点・申込の実務視点
dbt Analytics Engineer 認定の出題範囲、配点の考え方、申込から受験までの流れを、公式ドキュメントの...
dbt Cloud と dbt Core の違いと選び方:Analytics Engineer 試験に効く要点
dbt Cloud と dbt Core の機能差を、実務と資格対策の両面から整理。スケジューリング、IDE、RBAC、...
dbt プロジェクト構造ガイド: models / seeds / macros の実務レイアウト
Analytics Engineer 向けに、dbt プロジェクトのディレクトリ構造と命名規約、dbt_project....
dbt_project.yml の読み方:主要設定と命名を最短で掴む
dbt_project.yml の必須キー、命名解決(database.schema.identifier)、設定優先度...