dbt

dbtのpre-hook / post-hook徹底整理:実行前後のSQL差し込みの実務パターンと試験対策

2026-04-19
NicheeLab編集部

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とは用途が異なります。

  • 適用対象: モデル、スナップショット、シード(エフェメラルモデルは非対象)
  • 実行単位: 対象ノードごとに評価・実行(スキップされたノードでは実行されない)
  • 記述場所: モデルファイルのconfig()、dbt_project.yml(+pre-hook/+post-hook)
  • 内容: 生SQL文字列、Jinja式、マクロ呼び出し
  • 公式: Hooks(dbt Docs)に定義された安定機能

実行順序とトランザクションの扱い

dbt run全体では、on-run-startが最初に一度だけ実行された後、各ノードについてpre-hook → 本体SQL → post-hookの順に進み、最後にon-run-endが一度だけ実行されます。

多くのアダプタではノードの本体SQLとpre/post hookは同一トランザクション内で実行されます。設定でtransaction: false(サポートされるアダプタのみ)を指定すると、フックを独立トランザクションとして実行可能です。DML/DDLの自動コミット挙動はウェアハウス依存のため、権限付与やセッション設定などは必要に応じて分離するのが安全です。

  • pre-hook失敗時: ノードは失敗として扱われ、以降の本体SQL/post-hookは実行されない
  • post-hook失敗時: ノードは失敗、対象リレーションは既に作成・更新済みの可能性あり
  • 複数スコープに同一フックを定義するとマージされ、定義順序に従って上から順に実行される。順序が重要な場合は定義箇所を一元化する
  • DDLの自動コミットを行う倉庫(例: 一部のSnowflake DDL)では、トランザクション境界の影響を受けないものがある点に留意

dbt実行ライフサイクルとフックの位置づけ

dbt runon-run-startmodel Apre-hook / SQL(main) / post-hookmodel Bpre-hook / SQL(main) / post-hookseed Cpre-hook / SQL(load) / post-hookon-run-endrun done

代表ユースケース(権限付与、監査ログ、セッション設定など)

post-hookは新規作成・置換直後のリレーションに対する権限付与や統計再計算に適しています。pre-hookは実行前に必要な下準備(ステージングや一時テーブルのクリーニング)に向いています。

セッションやクエリ単位の設定は、フックだけでなくsql_headerやアダプタ固有の設定(例: Snowflakeのquery_tag)を併用すると安定します。

  • 権限付与(post-hook): grant select on {{ this }} to role ...
  • 監査ログ(pre/post): 監査テーブルに挿入してモデル名、環境、タイムスタンプを記録
  • 最適化・統計(post): Redshiftのanalyze/vacuum、Databricksのoptimize/analyze等
  • セッション設定(pre or sql_header): Snowflakeのquery_tag、warehouse切替等
  • ハウスキーピング(pre): ステージ領域やワークテーブルのクリーンアップ

設定方法と書き方パターン(dbt_project.yml / config() / マクロ)

フックはdbt_project.ymlでモデル階層に一括適用するか、個別のモデル内config()で指定できます。リストで複数記述し、上から順に実行されます。マクロ呼び出しも可能です。

アダプタが対応する場合、transaction: falseでフックを独立トランザクション化できます。権限付与やロギングなど、失敗時に本体のロールバックへ巻き込みたくない処理で有効です。

  • 一括適用: 権限付与や共通ロギングをdbt_project.ymlで集中管理
  • 個別適用: モデル固有の前処理/後処理をモデルファイル側のconfig()で管理
  • Jinja: this、target、var、env_varを使用可能。ログはlog()マクロで出力

設定例(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 %}

pre / post / on-runの比較と試験対策の観点

Analytics Engineer試験では、フックの適用粒度、実行タイミング、トランザクション境界の違いが典型論点です。どのユースケースにどのフックを選ぶべきかを即答できるようにしておきましょう。

特に、プロジェクト開始/終了で一度だけ記録したい監査はon-run-start/end、各モデルに付与が必要な権限はpost-hook、前処理のクリーンアップはpre-hookという棲み分けを覚えるのが効果的です。

  • ノード単位の処理はpre/post、ラン単位の処理はon-run
  • 権限管理はgrants機能が使えるなら優先。複雑ロジックはpost-hook
  • 失敗時のロールバック方針でtransaction設定を選ぶ
フック種別タイミング/粒度トランザクション主な用途
pre-hook各ノード実行の直前通常は本体SQLと同一。必要に応じて分離可(adapter依存)一時テーブル準備、クリーンアップ、セッション前提条件の設定
post-hook各ノード実行の直後通常は本体SQLと同一。分離で権限付与等を安全化GRANT、監査ログ、統計再計算
on-run-start / endラン開始時/終了時に1回単独で実行(ノードと独立)ラン全体の監査記録、環境初期化/後片付け

落とし穴とベストプラクティス

フックは便利な一方で、トランザクション境界や順序の取り扱いを誤ると意図しない副作用を招きます。以下を守ると安定します。

  • 権限付与はdbtのgrants設定がサポートされる場合はそちらを優先。post-hookは複雑なロールロジックや非対応アダプタで補完
  • フックSQLは冪等化(存在チェック、create or replace、grantの再実行許容)
  • 順序が重要なら定義箇所を一元化し、プロジェクト/モデル双方に重複定義しない
  • セッション全体へ適用したい設定はsql_headerやアダプタ提供の設定を優先(pre-hookはノード単位)
  • 共有監査テーブルの更新はキー重複回避やロック対策を行う
  • デバッグはdbt compileや--debug、log()出力、run-operationでマクロ単体検証

問題で確認

Analytics Engineer

問題 1

あるチームは、dbt runの開始時に監査テーブルへ1行だけ実行ログを入れ、各モデルが作成・更新された直後に必ず権限を付与したい。最も適切な構成はどれか。

  1. on-run-startで監査ログ、各モデルのpost-hookでGRANTを実行する
  2. 各モデルのpre-hookで監査ログ、on-run-endでGRANTを一括実行する
  3. on-run-startでGRANT、各モデルのpost-hookで監査ログを実行する
  4. 各モデルのpre-hookでGRANTと監査ログをまとめて実行する

正解: 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()マクロで実行時情報を出力して確認するのも有効です。

この記事で学んだ内容を問題で確認しましょう

16,000問以上の問題で実力チェック

無料で問題を解いてみる
この記事の著者

NicheeLab編集部

データエンジニアリング・クラウド資格の専門家。Databricks・Snowflake等の認定資格を保有し、実務経験に基づいた問題作成・解説を行っています。NicheeLab運営。


関連記事
dbt

dbt Model の基礎: SQL で定義する変換の最小単位

Analytics Engineer 向けに、dbt Model の定義、マテリアライゼーション、依存関係、インクリメン...

dbt

dbt Analytics Engineer 試験ガイド: 出題範囲・配点・申込の実務視点

dbt Analytics Engineer 認定の出題範囲、配点の考え方、申込から受験までの流れを、公式ドキュメントの...

dbt

dbt Cloud と dbt Core の違いと選び方:Analytics Engineer 試験に効く要点

dbt Cloud と dbt Core の機能差を、実務と資格対策の両面から整理。スケジューリング、IDE、RBAC、...

dbt

dbt プロジェクト構造ガイド: models / seeds / macros の実務レイアウト

Analytics Engineer 向けに、dbt プロジェクトのディレクトリ構造と命名規約、dbt_project....

dbt

dbt_project.yml の読み方:主要設定と命名を最短で掴む

dbt_project.yml の必須キー、命名解決(database.schema.identifier)、設定優先度...

dbtの記事一覧 (100件)
© 2026 NicheeLab All rights reserved.