DuckDB は単一ファイルまたはメモリ内で動作する組込み型データベースです。dbt-duckdb アダプターを使えば、クラウド DWH なしでローカルにモデルを検証し、高速に反復ができます。
本稿は実務と資格対策の両立を意識し、公式ドキュメントに沿った安定的な使い方に絞って、手戻りが起きやすい落とし穴を先回りで潰します。
dbt-duckdb は、dbt のモデルやテスト、スナップショットを DuckDB 上で実行するためのアダプターです。DuckDB はサーバ不要で、ローカルのファイル(.duckdb)やメモリ上にデータを保持できます。これにより、開発者はネットワークやクラウド課金に依存せず、手元で素早くモデリングの反復が可能になります。
試験観点では、マテリアライズ(view / table / incremental / ephemeral)、モデル間の依存、ソース定義、テスト・スナップショットなど dbt の普遍的な概念は DuckDB でも同様に問われます。DuckDB 固有の注意点(権限管理がない、同一ファイルの併行更新は避けるなど)を理解しておくと、実務でも試験でも混乱を避けられます。
dbt で DuckDB を使うには profiles.yml にアダプター固有の設定を書きます。最小限は type、path、schema です。拡張機能(extensions)や接続時設定(settings)を加えると、HTTP/Parquet の読み取りやメモリ制限などを制御できます。
ローカル開発フローの基本は「ソース定義 → モデル(staging/marts)→ テスト → スナップショット(必要に応じて)」です。まず view で軽くつないで形を整え、確定テーブルは table で固めるのが反復に向きます。
ローカル開発の典型フロー(dbt + DuckDB)
最小構成の profiles.yml と dbt_project.yml
# ~/.dbt/profiles.yml
duckdb:
outputs:
dev:
type: duckdb
path: ./local/dev.duckdb
schema: analytics
threads: 4
extensions:
- httpfs
- parquet
settings:
memory_limit: 2GB
target: dev
# dbt_project.yml
name: duckdb_local_lab
version: 1.0
profile: duckdb
models:
duckdb_local_lab:
+materialized: view
staging:
+schema: staging
marts:
+materialized: tableDuckDB 上でも dbt の標準マテリアライズ(view / table / incremental / ephemeral)が使えます。反復速度を優先するなら staging は view、確定させたいファクト・ディメンションは table が無難です。ephemeral は小さな前処理を呼び出し側へインライン展開したいときに有効です。
インクリメンタルモデルは append または delete+insert 戦略が安定です。unique_key を指定して、is_incremental() ブロックで取り込み条件を定義します。DuckDB とファイルソースを組み合わせる場合は、到着日時やファイルリストを基準に差分取り込みを設計します。
DuckDB 向けインクリメンタルモデルの例(delete+insert)
-- models/marts/fct_orders.sql
{{ config(
materialized='incremental',
unique_key='order_id',
incremental_strategy='delete+insert'
) }}
with src as (
select * from {{ ref('stg_orders') }}
{% if is_incremental() %}
where updated_at > (select coalesce(max(updated_at), '1970-01-01') from {{ this }})
{% endif %}
)
select
order_id,
customer_id,
order_date,
updated_at,
total_amount
from srcDuckDB は関数でファイルを直接読み込めます。ローカルなら read_csv_auto() や read_parquet()、リモートなら httpfs 拡張を有効化して HTTP/HTTPS 上のオブジェクトを参照します。拡張は profiles.yml の extensions に列挙します。
実務では、外部ファイルをすぐに取り込まず、まず view で直接参照してプロファイリングする手があります。型や欠損の傾向を把握できたら、確定テーブルへ CTAS(create table as select)するモデルを追加します。これにより、反復初期の不要な I/O を抑えられます。
CSV/Parquet をビューとして参照するモデル例
-- models/staging/stg_sales_files.sql
{{ config(materialized='view') }}
with p as (
-- ディレクトリ配下の Parquet をまとめて読み込む
select * from read_parquet('data/sales/*.parquet')
),
cs as (
-- リモート CSV(httpfs 拡張が有効であること)
select * from read_csv_auto('https://example.com/sales/latest.csv')
)
select * from p
union all
select * from csdbt の汎用テスト・カスタムテストは DuckDB でもそのまま動作します。スナップショットも SQL レベルの機能のため利用可能です。開発中は dbt test を小刻みに回し、不変キーや一意制約の欠損を早期に検知します。
CI では、リポジトリ同梱の profiles.yml を使用して一時ディレクトリに .duckdb を出力します。キャッシュ前提の長時間ジョブにせず、毎回クリーンに作り直す方がトラブルが少ないです。並列ジョブで同一ファイルを書かないようジョブごとにパスを分離します。
GitHub Actions での軽量 CI 例(DuckDB)
name: dbt-duckdb-ci
on:
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- run: pip install --upgrade pip && pip install dbt-duckdb
- name: dbt deps / seed / run / test
env:
DBT_PROFILES_DIR: ./.dbt
run: |
dbt deps
dbt seed --threads 4
dbt run --threads 4
dbt test --threads 4DuckDB で形を固めたら、Snowflake や Databricks SQL、Postgres などの DWH/DB に移すケースが多いです。その際は、接続形態、権限、同時実行、インクリメンタル戦略、型の差異に注意します。特定エンジン依存の関数はモデル層に閉じ込め、共通ロジックは macro と adapter.dispatch で抽象化すると移行が楽になります。
オブジェクト命名とクオート、スキーマの有無、時刻型の扱いは移行時の定番ハマりどころです。CI で本番アダプターを使ったモック実行を1本用意し、早い段階で差異を洗い出しましょう。
| 観点 | DuckDB(ローカル/組込み) | Postgres(サーバ型) | Snowflake(クラウド DWH) |
|---|---|---|---|
| 接続形態 | 単一プロセス/ファイル or メモリ | TCP 接続・常駐サーバ | マネージド・ウェアハウス |
| 権限管理 | 限定的(grants は実質無効) | ロール/権限あり | ロール/権限・RBAC |
| 起動/準備 | 即時(ファイルを開くだけ) | サービス起動が必要 | ウェアハウス起動・割当が必要 |
| 同時書込み | 単一プロセス推奨 | 複数クライアントで並行可 | 複数セッションで並行可 |
| コスト | ローカル実行で追加コストなし | インフラ運用コスト | 従量課金(コンピュート/ストレージ) |
| 増分戦略の一般度 | append / delete+insert が安定 | MERGE 含め広く一般的 | MERGE 戦略が一般的 |
Analytics Engineer
問題 1
ローカル環境で dbt-duckdb を使い、HTTP 上の CSV を view モデルから参照したい。正しい設定の組み合わせはどれか。
正解: A
HTTP/HTTPS のファイル参照には DuckDB の httpfs 拡張が必要です。dbt のプロジェクト設定ではなく、profiles.yml 側の extensions で有効化し、モデル内で read_csv_auto() などの関数を使って参照します。:memory: はメモリ内 DB を意味しますが、外部ファイル参照の可否とは別問題です。seed はローカル静的ファイルを取り込む仕組みで、HTTP の直接取り込みではありません。
dbt-duckdb で grants 設定は有効ですか?
DuckDB はサーバ型の権限モデルを持たないため、dbt の grants 設定は実質的に効果がありません。権限管理が必要な本番環境では、Snowflake や Postgres などのアダプターに切り替えて対応します。
同じ .duckdb ファイルを複数の dbt 実行で同時に更新してよいですか?
推奨されません。単一ファイルに対する同時書き込みは競合の原因になります。ジョブを直列化するか、実行ごとに別ファイルを使い分けてください。
メモリ使用量が心配です。制御できますか?
profiles.yml の settings で memory_limit などの接続時設定を指定できます。DuckDB の設定に委ねられるため、環境に合わせて適切な上限を設定してください。
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)、設定優先度...