dbt

dbt insert_overwrite 戦略で実現するパーティション単位の洗替え

2026-04-19
NicheeLab編集部

大量データの日次更新で全表を作り直すのは非現実的です。dbt の insert_overwrite 戦略は、影響のあるパーティションだけを丸ごと置き換え、他のパーティションをそのまま保つことで、更新コストとリスクを抑えます。

ただし、この戦略はアダプタ依存で挙動や前提が異なります。試験対策では「どのアダプタで使え、どんな前提が必要か」を確実に押さえ、実務では「どのパーティションを洗替えるか」を明示的に制御することが重要です。

insert_overwrite 戦略の要点

dbt の incremental materialization における insert_overwrite は、指定したパーティションのみを新しい結果で置き換える更新戦略です。上流で当日または一部期間のデータが差し替わるケースに向いており、全表再作成より高速・低コストに収まります。

重要なのは「置き換え対象パーティションを、SELECT の結果として明示的に限定する」点です。モデルのクエリが返すパーティションだけが洗替え対象になるため、is_incremental() ブロックで期間やキーを絞り込みます。

  • メリット: 影響パーティションのみ更新、他は不変。ジョブ時間・コストとロックの影響を抑制。
  • 条件: アダプタ側で INSERT OVERWRITE 相当の構文や動作をサポートし、テーブルがパーティション化されていること。
  • 設計ポイント: 更新対象パーティションの決定ロジックをクエリで表現し、アイドポテンシー(同じ処理を繰り返しても結果が安定)を確保する。

dbt モデル設定の最小例(概念)

{{ config(
  materialized='incremental',
  incremental_strategy='insert_overwrite',
  partition_by={'field': 'ds', 'data_type': 'date'}
) }}

with src as (
  select * from {{ ref('stg_events') }}
)

select
  cast(event_time as date) as ds,
  user_id,
  count(*) as events
from src
{% if is_incremental() %}
where cast(event_time as date) >= current_date()  -- 例: 当日パーティションのみ
{% endif %}
group by 1,2

対応アダプタと前提条件

insert_overwrite はアダプタ依存の戦略です。公式ドキュメントの対象アダプタでのみ安定利用を想定してください。少なくとも BigQuery と Spark/Databricks では、パーティション化テーブルを前提とした INSERT OVERWRITE 振る舞いが利用可能です(詳細は dbt Docs を参照)。

Databricks/Spark 環境では、パーティション上書きの粒度制御に関わるセッション設定(dynamic partition overwrite)を適切に有効化します。BigQuery はクエリで返すパーティションが上書き対象となり、DML 単位で原子的に反映されます。

  • どのアダプタが対応かを必ず確認(dbt Docs: Adapters ごとの incremental 戦略一覧)。
  • テーブルは明示的にパーティション化しておく(partition_by 設定)。
  • 上書き対象を過不足なく絞り込む WHERE 句(またはサブクエリ)を実装。
アダプタdbt での insert_overwrite 対応必須前提(パーティション等)原子的保証
BigQuery対応ありpartition_by が必須(date/datetime/timestamp ベースが一般的)ステートメント単位で原子的
Databricks/Spark(Delta 推奨)対応ありpartition_by が必須。dynamic partition overwrite を推奨Delta の ACID により原子的
Snowflake原則未対応(dbt の専用戦略として)MERGE または delete+insert 等を利用MERGE はトランザクション内で原子的
Redshift未対応代替として MERGE/CTE ベースの upsertトランザクション制御に依存

Databricks/Spark での dynamic partition overwrite 有効化例

{{ config(
  pre_hook=[
    "SET spark.sql.sources.partitionOverwriteMode=dynamic"
  ]
) }}

パーティション単位の洗替え設計

洗替え対象をどう決めるかが設計の核心です。多くのケースでは、上流取り込みの到着範囲(例: 当日分、直近 N 日、あるいは変更を検知したキーに紐づく日付)を根拠にパーティションを特定します。

SELECT が返す行のパーティションだけが置換対象となるため、is_incremental() 節で対象期間を限定し、同じジョブを再実行しても同一結果が得られるように重複排除・集約を含むロジックを組み込みます。

  • 対象パーティションの同定方法: 期間境界(min/max)、変更キー照会、到着フラグ。
  • アイドポテンシー: 重複行の除外や最新レコード選択(window 関数等)をクエリに含める。
  • 安全弁: 期間が想定以上に広がらないよう、max 書き換え日数を定数化。

洗替え対象パーティションの流れ(概念図)

Raw/Staging新着データChanged partitionsds in {2026-04-17}dbt model (insert_overwrite)is_incremental() で ds 限定 / 集約・重複排除既存パーティション置換ds=2026-04-17 を洗替え新規パーティション必要なら作成is_incremental() で ds を限定し、集約/重複排除で決定版を生成した結果が対象パーティションを洗替え

変更検知で対象パーティションを限定するクエリ断片(概念)

with src as (
  select * from {{ ref('stg_orders') }}
),
changed as (
  -- 上流到着ベースで対象パーティションを限定
  select distinct cast(updated_at as date) as ds
  from src
  {% if is_incremental() %}
  where _ingested_at >= {{ var('low_watermark', "timestamp_sub(current_timestamp(), interval 1 day)") }}
  {% endif %}
)
select /* 対象 ds のみ返すことで、その ds が洗替え対象になる */
  cast(order_date as date) as ds,
  customer_id,
  sum(amount) as revenue
from src
where cast(order_date as date) in (select ds from changed)
group by 1,2

実装パターン(BigQuery)

BigQuery では INSERT OVERWRITE DML とパーティション化テーブルの組み合わせにより、クエリが返したパーティションのみが原子的に置換されます。dbt 側では partition_by を設定し、is_incremental() 内で対象期間を限定します。

クラスタリングは任意ですが、スキャン効率のため partition_by と組み合わせて設計するのが無難です。長期のバックフィルでは期間をチャンクに分割して複数回に分けるのが実務的です。

  • partition_by は必須。date/timestamp 型の列が定石。
  • is_incremental() 節で返す行の ds を限定することが洗替え範囲の唯一の根拠。
  • バックフィルは期間を小分けにして実行(例: 7 日ずつ)。

dbt モデル例(BigQuery、日次パーティションを洗替え)

{{ config(
  materialized='incremental',
  incremental_strategy='insert_overwrite',
  partition_by={'field': 'ds', 'data_type': 'date'},
  cluster_by=['user_id']
) }}

with src as (
  select * from {{ ref('stg_events') }}
),
changed as (
  -- 上流の到着基準で対象 ds を限定
  select distinct cast(event_time as date) as ds
  from src
  {% if is_incremental() %}
  where _ingested_at >= {{ var('low_watermark', "timestamp_sub(current_timestamp(), interval 1 day)") }}
  {% endif %}
)
select
  cast(event_time as date) as ds,
  user_id,
  count(*) as events
from src
where cast(event_time as date) in (select ds from changed)
group by 1,2

実装パターン(Databricks/Delta)

Databricks(Spark)では、Delta Lake の ACID により INSERT OVERWRITE の原子的置換が可能です。dynamic partition overwrite を有効にすると、書き出したパーティションのみが置換され、他のパーティションは不変のまま残ります。

クラスタやジョブのスコープで spark.sql.sources.partitionOverwriteMode=dynamic を設定するのが安全です。dbt では pre_hook を使ってセッション設定する方法もよく用いられます。

  • ファイル形式は Delta を推奨(ACID と DML 機能が安定)。
  • dynamic partition overwrite を有効化(クラスタ設定または dbt の pre_hook)。
  • 対象 ds を厳密に限定し、集約や重複排除で決定版を返す。

dbt モデル例(Databricks/Delta、動的パーティション洗替え)

{{ config(
  materialized='incremental',
  incremental_strategy='insert_overwrite',
  partition_by=['ds'],
  file_format='delta',
  pre_hook=[
    "SET spark.sql.sources.partitionOverwriteMode=dynamic"
  ]
) }}

with src as (
  select * from {{ ref('stg_events') }}
),
changed as (
  -- 直近 1 日の到着で変動した ds のみ
  select distinct cast(event_time as date) as ds
  from src
  {% if is_incremental() %}
  where load_date >= date_add(current_date(), -1)
  {% endif %}
)
select
  cast(event_time as date) as ds,
  user_id,
  count(*) as events
from src
where cast(event_time as date) in (select ds from changed)
group by 1,2

運用ノウハウと試験対策ポイント

運用では、広すぎる洗替えによるコスト・ロック増大を避けるため、最大期間のガードレールや、上限を超えた場合に失敗させるプリチェックを用意します。監視では、更新対象パーティションの件数・範囲、ジョブの所要時間、スキップ検知を記録します。

試験対策としては、次を押さえてください。1) insert_overwrite はアダプタ依存であり、partition_by が必須、2) 上書き対象は SELECT が返すパーティションに限られる、3) Databricks では dynamic partition overwrite の設定が重要、4) Snowflake 等では MERGE を使うのが一般的。

  • ガードレール: 例えば対象 ds の個数が 10 を超えたら失敗させる。
  • バックフィルはチャンクに分けて複数回実行し、各回の対象を明示化。
  • 監査列(作成時刻・ソーススナップショット ID)を付与してトラブルシュートを容易にする。

変数を使ったバックフィル(CLI とモデル側の連携)

-- 実行例(7 日分バックフィル)
-- dbt run --select fact_events --vars "start_date: 2026-04-10, end_date: 2026-04-16"

-- モデル側の is_incremental() フィルタ(アダプタ共通の概念例)
{% if is_incremental() %}
where ds between {{ var('start_date', 'current_date()') }} and {{ var('end_date', 'current_date()') }}
{% endif %}

問題で確認

Analytics Engineer

問題 1

Databricks(Delta)で日次パーティション ds のみを洗替えたい。dbt モデルの更新で、影響のある ds だけを原子的に置き換え、他のパーティションには触れない構成として最も適切なのはどれか。

  1. materialized=incremental、incremental_strategy=insert_overwrite、partition_by=['ds'] を設定し、pre_hook で spark.sql.sources.partitionOverwriteMode=dynamic を有効化する
  2. materialized=incremental、incremental_strategy=append とし、WHERE 句で ds を限定する
  3. materialized=incremental、incremental_strategy=merge のみを設定し、partition_by なしで実行する
  4. CREATE OR REPLACE TABLE AS SELECT で全表を毎回作り直す

正解: A

Databricks/Delta でパーティション単位の置換を安全に行うには、dbt の insert_overwrite 戦略とパーティション化の併用が前提。さらに dynamic partition overwrite を有効化して、返却したパーティションだけを置換する。append は古い行を残すため洗替えにならず、merge はパーティション単位の丸ごと置換が目的のケースでは不要な行粒度の突合が発生しうる。

よくある質問

Snowflake でも insert_overwrite は使えますか?

dbt の insert_overwrite 戦略は主に BigQuery と Spark/Databricks での利用が前提です。Snowflake では通常 MERGE(または delete+insert)で同等の要件を満たします。アダプタの対応状況は dbt 公式ドキュメントを確認してください。

対象パーティションの広がりをどう抑制すべきですか?

is_incremental() 節で日付範囲や変更キーを用いて厳密に限定し、最大パーティション数の上限チェックを pre_hook で行うと安全です。想定外に広い場合は失敗させ、オペレータ確認を挟む運用が有効です。

重複や順序入れ替えが起こるソースに対しても安全ですか?

安全にするには、洗替え対象パーティション内で決定版を生成するロジック(重複排除、最新優先のウィンドウ関数、集約)を必ず含めてください。insert_overwrite 自体は置換の器であり、正しさは SELECT の内容に依存します。

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

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.