List
지난 글에서는 SQLite 환경에서 dbt 프로젝트를 세팅하고, 첫 번째 모델을 만들어 실행해보았습니다.
이번 글에서는 dbt의 7대 핵심 구성요소를 하나씩 짚으며, 각각이 데이터 파이프라인에서 어떤 역할을 하는지, 그리고 서로 어떻게 맞물려 동작하는지를 살펴보겠습니다.
왜 구성요소를 이해해야 할까?
dbt는 단순히 “쿼리를 실행하는 도구”가 아니라, 데이터 변환 과정을 코드처럼 관리하고, 테스트·문서화·계보 추적까지 통합하는 데이터 모델링 프레임워크입니다.
구성요소의 의미를 이해하면, 팀 내에서 일관성 있는 설계·운영이 가능해집니다.
dbt의 7대 구성요소
구성요소 | 역할 | 실무 포인트 |
Models | 데이터 변환 로직의 최소 단위 | 쿼리·의존성 관리 |
Sources | 원본 데이터 정의 | 위치 고정·계보 추적 |
Seeds | CSV 참조 데이터 | 코드와 함께 버전 관리 |
Snapshots | 변경 이력 관리 | Slowly Changing Dimension |
Materializations | 결과 저장 방식 | 성능·운영 전략 선택 |
Tests | 데이터 품질 검증 | unique, not_null 등 |
Documentation | 모델·소스 문서화 | 계보와 설명 자동화 |
1. Models — 변환 로직의 최소 단위
모델(Model)은 dbt에서 데이터 변환 로직의 최소 단위입니다.
한 모델은 하나의 SQL 파일이며, 이를 실행하면 테이블(Table) 또는 뷰(View)로 생성됩니다.
주요 특징
•
SQL로 작성되며 Jinja 템플릿({{ }}) 문법과 함께 사용 가능
•
폴더 구조로 레이어 구분 가능 (staging, core, mart 등)
•
config를 통해 저장 방식, 태그, 결과물 이름 등을 제어 가능
예시 SQL
-- models/staging/stg_orders.sql
-- 목적:
-- 원본 주문 데이터(raw.orders)를 받아
-- 컬럼명·타입을 표준화하고
-- 향후 조인·집계가 쉽게 정리된 결과로 만든다.
{{ config(
materialized = 'view' -- 결과를 뷰로 생성
) }}
select
order_id, -- 주문 ID (원본 그대로 사용)
customer_id, -- 고객 ID
cast(order_ts as timestamp) as order_time -- 문자열/숫자 → timestamp 변환
from {{ source('raw', 'orders') }} -- 원본 테이블 참조 (하드코딩 방지)
SQL
복사
예시 설명
•
원본 데이터 불러오기
◦
source('raw', 'orders')는 sources.yml에 등록된 raw 레이어의 orders 테이블을 참조
◦
하드코딩 대신 소스 정의를 사용하므로, 환경이 바뀌어도 수정할 SQL이 최소화
•
컬럼 표준화
◦
order_ts를 timestamp 형식으로 변환해 order_time이라는 표준 이벤트 시간 컬럼을 생성
◦
이후 모든 다운스트림 모델에서 동일한 시간 컬럼을 참조 가능
•
결과 저장 방식 설정
◦
materialized='view' → 개발 단계에서 빠르게 반영 가능, 스키마 변경·테스트에 유리
◦
운영에서는 필요 시 table 또는 incremental로 변경
구성요소 설명
구성 요소 | 역할 | 고려사항 |
{{ config(...) }} | 모델 실행 시 동작 방식 정의 (저장 방식, 태그, alias 등) | 저장 방식에 따라 성능·비용이 달라짐 |
source() | 원본 데이터 참조 | sources.yml 정의와 반드시 일치해야 함 |
cast(... as timestamp) | 타입 변환 | DB별 타임스탬프 포맷 차이 주의 |
materialized='view' | 결과를 뷰로 생성 | 빠른 개발·테스트에 유리, 데이터 양 많으면 table 고려 |
2. Sources — 원본 데이터 고정점
Source는 dbt에서 원본 데이터의 위치와 구조를 정의하는 고정점 역할을 합니다.
SQL 안에서 하드코딩된 스키마·테이블명을 쓰지 않고, YAML 설정을 통해 중앙에서 관리합니다.
주요 특징
•
환경별(DB, 스키마, 테이블명) 변경에 유연
•
데이터 품질 검사(test)를 source 단위에서 바로 적용 가능
•
변경 추적 가능 → 원본 스키마나 필드 변경 시 알림
예시 설정
# models/sources.yml
version: 2
sources:
- name: raw # 원본 스키마 이름 (논리적)
description: "원본 시스템에서 추출된 데이터 레이어"
tables:
- name: orders
description: "주문 거래 로그 원본 데이터"
columns:
- name: order_id
description: "주문 ID, 고유 식별자"
tests: # 데이터 품질 테스트
- not_null
- unique
- name: customers
description: "고객 기본 정보"
YAML
복사
예시 SQL
-- models/staging/stg_orders.sql
{{ config(materialized='view') }}
select
order_id,
customer_id,
cast(order_ts as timestamp) as order_time
from {{ source('raw', 'orders') }} -- 원본 데이터 참조 (YAML 정의 기반)
SQL
복사
예시 설명
•
원본 데이터 위치 정의
◦
sources.yml에서 raw.orders를 정의하고, 해당 DB/스키마/테이블명을 명시
◦
실제 DB 접속 시에는 profiles.yml의 연결 정보와 매핑
•
SQL에서 간단하게 참조
◦
source('raw', 'orders') → 하드코딩 없이 raw.orders를 참조
◦
환경이 dev/prod로 바뀌어도 YAML만 수정하면 모든 모델에 반영
•
데이터 품질 관리
◦
not_null, unique 같은 테스트를 소스 정의에 포함
◦
dbt test --select source:raw.orders로 품질 검사 가능
구성요소 설명
구성 요소 | 역할 | 고려 사항 |
sources: | 원본 데이터 그룹 정의 | 프로젝트별 논리 이름과 실제 DB 매핑 필요 |
tables: | 원본 테이블 목록 | 모든 원본 테이블을 여기에 등록 |
columns: | 컬럼별 설명 및 테스트 정의 | 컬럼 테스트는 데이터 품질 관리 핵심 |
source() | SQL에서 source 참조 | YAML 정의와 반드시 이름·스펠링 일치 |
3. Seeds — CSV도 코드처럼 관리
Seed는 CSV 파일을 테이블로 로드하는 기능입니다.
원래 CSV를 DB에 넣으려면 별도의 로드 스크립트나 툴이 필요하지만,
dbt에서는 CSV 파일을 data/ 폴더에 넣고 한 줄 명령으로 테이블로 변환할 수 있습니다.
주요 특징
•
CSV 파일도 Git에 버전 관리 가능
•
배포 환경(dev/prod)에서 동일한 데이터 보장
•
초기 코드/데이터 로딩, 기준값(코드 테이블) 관리에 유용
예시 CSV
# data/country_codes.csv
country_code,country_name
KR,South Korea
US,United States
JP,Japan
SQL
복사
예시 실행
# seeds 로드
dbt seed
Bash
복사
예시 SQL
-- models/marts/country_summary.sql
{{ config(materialized='table') }}
select
cc.country_name,
count(o.order_id) as total_orders
from {{ ref('country_codes') }} as cc -- CSV를 테이블처럼 참조
left join {{ ref('orders') }} as o
on cc.country_code = o.country_code
group by cc.country_name
SQL
복사
예시 설명
•
CSV → DB 테이블 로드
◦
data/country_codes.csv를 dbt seed로 실행하면 DB에 country_codes 테이블 생성
•
일관성 있는 기준 데이터 관리
◦
국가 코드, 상품 카테고리 코드, 상태 코드 등 변하지 않는 기준값을 Git에 저장
•
모델에서 참조 가능
◦
ref('country_codes')를 사용하여 다른 테이블과 조인
구성요소 설명
구성 요소 | 역할 | 고려 사항 |
data/ | seed CSV 저장 폴더 | 파일명 = 생성될 테이블명 |
CSV 헤더 | 컬럼명 정의 | SQL에서 그대로 사용 |
dbt seed | CSV → 테이블 로드 명령 | 실행 시 기존 데이터 덮어씀 |
ref() | seed 참조 함수 | 모델명과 동일한 이름 사용 |
4. Snapshots — 변경 이력 자동 관리
Snapshot은 테이블의 변경 이력(History)을 자동으로 관리하는 기능입니다.
예를 들어 고객의 주소, 주문 상태, 상품 가격처럼 시간이 지나면서 변하는 값을
"변경 전"과 "변경 후"를 모두 보관하고 싶을 때 사용합니다.
주요 특징
•
변경 감지 로직(변경된 행만 식별)
•
변경 시점 기록
•
기존 행 보존이 필요하지만, dbt의 Snapshot은 이를 SQL 한 장과 설정만으로 해결합니다.
예시 설정
-- snapshots/customers_snapshot.sql
{% snapshot customers_snapshot %}
{{
config(
target_schema='snapshots', -- 이력 테이블 저장 위치
unique_key='customer_id', -- 변경 여부 판별 기준
strategy='check', -- 'check' 또는 'timestamp'
check_cols=['email', 'address'] -- 변경 감지할 컬럼
)
}}
select
customer_id,
email,
address,
updated_at
from {{ source('raw', 'customers') }}
{% endsnapshot %}
SQL
복사
예시 실행
# Snapshot 실행
dbt snapshot
Bash
복사
테이블 예시
customer_id | email | address | dbt_valid_from | dbt_valid_to |
1001 | Seoul, Korea | 2024-01-01 00:00:00 | 2024-02-15 10:20:00 | |
1001 | Busan, Korea | 2024-02-15 10:20:00 | null |
예시 설명
•
원본 테이블에서 고객 정보 조회
•
customer_id를 기준으로 기존 Snapshot 데이터와 비교
•
email 또는 address 컬럼 값이 변경되면,
◦
기존 행은 dbt_valid_to에 변경 시각을 기록
◦
새 행을 dbt_valid_from 시각과 함께 삽입
•
모든 변경 이력은 snapshots.customers_snapshot 테이블에 누적 저장
구성요소 설명
구성 요소 | 역할 | 고려 사항 |
snapshots/ | Snapshot SQL 파일 저장 폴더 | models 폴더와 별도로 관리 |
config() | Snapshot 동작 방식 정의 | strategy와 unique_key는 필수 |
strategy | 변경 감지 방식 | check(컬럼 비교) / timestamp(갱신 시각 기반) |
check_cols | 변경 여부를 확인할 컬럼 목록 | 민감 데이터만 지정하면 불필요한 변경 감지 방지 |
dbt snapshot | Snapshot 실행 명령 | 주기적으로 실행해야 이력 축적 가능 |
5. Materializations — 저장 전략 선택
Materialization은 모델 실행 결과를 어떤 형태로 데이터베이스에 저장할지를 결정하는 방법입니다.
dbt에서는 모델을 SQL로 작성하더라도, 그 결과를 View, Table, Incremental, Ephemeral 중 원하는 형태로 만들 수 있습니다.
즉, "쿼리 결과를 어떻게 보관할지"를 설정하는 단계입니다.
주요 Materialization 유형과 특징
유형 | 특징 | 장점 | 단점 | 활용 예시 |
view | 쿼리 정의만 저장, 데이터는 즉시 조회 | 항상 최신 데이터 반영 | 조회 시 매번 쿼리 실행 | 경량 변환, Staging 레이어 |
table | 쿼리 실행 결과를 물리 테이블로 저장 | 빠른 조회 속도 | 변경 시 전체 재생성 필요 | 집계, 마트(Mart) 모델 |
incremental | 새 데이터만 추가/갱신 | 대규모 데이터 처리에 효율적 | 증분 조건 관리 필요 | 이벤트 로그, Append-only 데이터 |
ephemeral | 물리 저장 없이 다른 모델에 인라인 | 중간 계산 용도에 최적 | 단독 조회 불가 | 복잡한 파이프라인 내부 조인 |
예시 모델
1.
view
-- models/stg_orders.sql
{{ config(materialized='view') }}
select
order_id,
customer_id,
cast(order_ts as timestamp) as order_time
from {{ source('raw', 'orders') }}
SQL
복사
2.
table
-- models/fct_orders.sql
{{ config(materialized='table') }}
select
order_id,
customer_id,
sum(amount) as total_amount
from {{ ref('stg_orders') }}
group by order_id, customer_id
SQL
복사
3.
incremental
-- models/inc_orders.sql
{{ config(
materialized='incremental',
unique_key='order_id'
) }}
select
order_id,
customer_id,
sum(amount) as total_amount
from {{ source('raw', 'orders') }}
{% if is_incremental() %}
where order_ts > (select max(order_time) from {{ this }})
{% endif %}
group by order_id, customer_id
SQL
복사
예시 설명
•
stg_orders
◦
원본 데이터를 변환한 뷰(View) 생성 → 항상 최신 데이터 반영
•
fct_orders
◦
집계 결과를 테이블(Table)로 저장 → 실행 시 전체 재생성
•
inc_orders
◦
증분(Incremetal) 방식 → 새로 들어온 데이터만 추가 처리
구성요소 설명
구성 요소 | 역할 | 초보자 주의 포인트 |
config(materialized=...) | Materialization 지정 | 기본값은 view |
ref() | 다른 모델 참조 | ref를 쓰면 실행 순서 자동 관리 |
is_incremental() | 증분 실행 시 True | 증분 조건을 명확히 작성해야 함 |
this | 현재 모델의 DB 객체 참조 | 증분 비교 시 유용 |
6. Tests — 데이터 품질 보장
dbt의 Tests는 모델이 만든 결과가 기대하는 조건을 충족하는지 자동으로 검증하는 기능입니다.
데이터 변환이 아무리 복잡해도, 품질이 담보되지 않으면 신뢰할 수 없습니다.
dbt는 SQL 기반으로 작성한 규칙을 실행해, 오류나 결측 데이터를 사전에 발견하도록 도와줍니다.
예시1 - 기본 테스트 (Not Null & Unique)
# models/core/customers.yml
version: 2 # dbt YAML 메타데이터 스키마 버전
models: # 테스트를 적용할 모델 목록
- name: customers
description: "고객 정보 테이블"
columns:
- name: customer_id
description: "고유 고객 식별자"
tests: # dbt 내장 테스트 키워드 (별도 SQL 작성 없이 사용 가능)
- not_null # 모든 customer_id가 반드시 존재해야 함
- unique # 중복된 customer_id가 없어야 함
YAML
복사
예시2 - 커스텀 조건 테스트
-- tests/positive_order_amount.sql
select *
from {{ ref('orders') }} # 테스트 대상 모델 참조
where amount <= 0 # 주문 금액이 0 이하인 경우를 실패 조건으로 지정
#쿼리 결과가 한 행이라도 있으면 테스트 실패로 처리
SQL
복사
예시 설명
•
내장 테스트
◦
YAML에서 짧게 정의
◦
null, unique, accepted_values 등 기본 품질 규칙 빠르게 적용
•
커스텀 테스트
◦
SQL 파일로 직접 작성
◦
비즈니스 규칙(예: 주문 금액 양수, 날짜 범위 제한 등) 반영 가능
7. Documentation — 지식의 공유와 계보 추적
dbt의 Documentation 기능은 단순한 주석을 넘어, 데이터 모델, 컬럼, 소스의 의미와 의도를 체계적으로 기록하고 데이터 계보(Lineage)를 자동으로 시각화합니다.
이 덕분에 새로운 팀원이 합류하거나, BI 분석가가 쿼리를 작성할 때도 “이 데이터가 어디서 왔고, 어떻게 가공됐는지”를 한눈에 파악할 수 있습니다.
예시1 - 모델 및 컬럼 문서화
# models/core/orders.yml
# 이 정보는 dbt docs generate 시 HTML 문서로 변환되어 검색 가능
version: 2
models:
- name: orders
# description -> 모델 또는 컬럼의 의미, 가공 방식, 주의사항 기록
description: "고객 주문 내역 테이블. 원본 데이터는 raw.orders에서 가져와 가공."
columns: # 각 컬럼별 설명을 개별적으로 추가
- name: order_id
description: "고유 주문 식별자"
- name: customer_id
description: "주문한 고객의 ID"
- name: order_date
description: "주문이 생성된 날짜"
- name: total_amount
description: "주문 총 금액(할인, 세금 포함)"
YAML
복사
예시2 - 소스(Source) 문서화
# models/staging/stg_sources.yml
# 원본 테이블의 역할과 생성 주기 등도 함께 기재 가능
version: 2
sources: # 외부/원본 데이터에 대한 설명을 추가
- name: raw
description: "원본 데이터베이스 스키마"
tables:
- name: orders
description: "주문 원본 테이블 (운영 DB에서 추출)"
YAML
복사
문서 생성과 계보 확인
dbt docs generate # 문서 파일 생성
dbt docs serve # 로컬 웹 서버로 문서 확인
Bash
복사
예시 설명
•
데이터 맥락(Context) 보존
◦
수개월 후에도 “이 컬럼이 왜 이렇게 계산됐는지” 이해 가능
•
협업 속도 향상
◦
데이터 정의서를 별도로 작성·관리할 필요 없이, dbt 코드와 함께 버전 관리
•
데이터 계보 추적
◦
ETL 파이프라인을 블랙박스처럼 쓰지 않고, 데이터 흐름을 투명하게 공개
구성요소 간 연결 흐름
flowchart LR A[Sources<br/>원본 데이터] --> B[(Seeds<br/>CSV 참조 데이터)] A --> C[Staging Models<br/>표준화 변환] B --> C C --> D[Core Models<br/>비즈니스 로직] D --> E[Mart Models<br/>최종 분석 테이블] A --> F[Snapshots<br/>변경 이력] classDef source fill:#E3F2FD,stroke:#1565C0,stroke-width:1px; classDef seed fill:#FFF3E0,stroke:#EF6C00,stroke-width:1px; classDef staging fill:#E8F5E9,stroke:#2E7D32,stroke-width:1px; classDef core fill:#F3E5F5,stroke:#6A1B9A,stroke-width:1px; classDef mart fill:#FCE4EC,stroke:#AD1457,stroke-width:1px; classDef snapshot fill:#FFFDE7,stroke:#FBC02D,stroke-width:1px; class A source; class B seed; class C staging; class D core; class E mart; class F snapshot;
Mermaid
복사
Sources — 시작점
•
외부 또는 원본 데이터베이스의 테이블/뷰
•
ETL에서 Extract 단계에 해당
•
ex) 운영 DB의 orders 테이블
Seeds — 보조 참조 데이터
•
CSV 파일을 코드로 관리하고 DB에 로드
•
외부 시스템 호출 없이, 변환 시 참조할 고정 데이터 제공
•
ex) 국가 코드 매핑표, 카테고리 정의
Staging Models — 원본 데이터 표준화
•
소스 데이터를 그대로 쓰지 않고 타입 변환, 컬럼명 표준화, 불필요 컬럼 제거
•
모든 변환의 출발점 → 이후 모델들이 안정적으로 참조 가능
•
ex) stg_orders.sql (order_ts → timestamp 변환)
Core Models — 비즈니스 로직 반영
•
도메인별 핵심 지표, 집계, 가공 로직 적용
•
분석에서 직접 활용 가능한 중간 데이터 세트
•
ex) 월별 매출 집계, 고객 생애 가치(LTV) 계산
Mart Models — 최종 분석/리포트용
•
BI, 대시보드, 리포팅 툴에서 바로 쓸 수 있는 형태
•
ex) 마케팅 팀용 퍼널 분석 테이블
Snapshots — 변경 이력 축적
•
Slowly Changing Dimensions(SCD) 관리
•
소스 데이터의 값이 변할 때, 이전 상태를 보존
•
ex) 고객 주소 변경 이력
Materializations — 저장 전략
•
모델 실행 결과를 Table / View / Incremental / Ephemeral 중 선택
•
성능·비용·데이터 신선도 요구사항에 맞게 조정
Tests · Documentation — 품질과 이해도 보장
•
Tests: null, unique, foreign key 등 데이터 무결성 검증
•
Documentation: 모델·컬럼·소스 설명과 계보(Lineage) 자동 생성
마무리
이번 글에서는 dbt의 7대 핵심 구성요소를 하나씩 살펴보며, 각 요소가 데이터 파이프라인 속에서 어떤 역할을 하는지 구체적으로 알아봤습니다. Sources로 시작해 Documentation까지 이어지는 흐름을 이해하면, 단순 쿼리 관리 이상의 구조적이고 재사용 가능한 데이터 모델링을 설계할 수 있습니다.
다음 글에서는 이러한 모델과 파이프라인이 안정적으로 운영되도록 보장하는 데이터 품질 관리에 도움이 되는 테스트 기능을 자세히 알아보겠습니다.