지난 글에서는 SQLite 환경에서 dbt 프로젝트를 세팅하고, 첫 번째 모델을 만들어 실행해보았습니다.
이번 글에서는 dbt의 7대 핵심 구성요소를 하나씩 짚으며, 각각이 데이터 파이프라인에서 어떤 역할을 하는지, 그리고 서로 어떻게 맞물려 동작하는지를 살펴보겠습니다.
왜 구성요소를 이해해야 할까?
dbt는 단순히 “쿼리를 실행하는 도구”가 아니라, 데이터 변환 과정을 코드처럼 관리하고, 테스트·문서화·계보 추적까지 통합하는 데이터 모델링 프레임워크입니다.
구성요소의 의미를 이해하면, 팀 내에서 일관성 있는 설계·운영이 가능해집니다.
dbt의 7대 구성요소
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') }} -- 원본 테이블 참조 (하드코딩 방지)
예시 설명
- 원본 데이터 불러오기
source('raw', 'orders')는sources.yml에 등록된 raw 레이어의 orders 테이블을 참조- 하드코딩 대신 소스 정의를 사용하므로, 환경이 바뀌어도 수정할 SQL이 최소화
- 컬럼 표준화
order_ts를timestamp형식으로 변환해order_time이라는 표준 이벤트 시간 컬럼을 생성- 이후 모든 다운스트림 모델에서 동일한 시간 컬럼을 참조 가능
- 결과 저장 방식 설정
materialized='view'→ 개발 단계에서 빠르게 반영 가능, 스키마 변경·테스트에 유리- 운영에서는 필요 시
table또는incremental로 변경
구성요소 설명
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: "고객 기본 정보"
예시 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 정의 기반)예시 설명
- 원본 데이터 위치 정의
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로 품질 검사 가능
구성요소 설명
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예시 실행
# seeds 로드
dbt seed예시 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예시 설명
- CSV → DB 테이블 로드
data/country_codes.csv를dbt seed로 실행하면 DB에country_codes테이블 생성
- 일관성 있는 기준 데이터 관리
- 국가 코드, 상품 카테고리 코드, 상태 코드 등 변하지 않는 기준값을 Git에 저장
- 모델에서 참조 가능
ref('country_codes')를 사용하여 다른 테이블과 조인
구성요소 설명
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 %}예시 실행
# Snapshot 실행
dbt snapshot테이블 예시
예시 설명
- 원본 테이블에서 고객 정보 조회
customer_id를 기준으로 기존 Snapshot 데이터와 비교email또는address컬럼 값이 변경되면,- 기존 행은
dbt_valid_to에 변경 시각을 기록 - 새 행을
dbt_valid_from시각과 함께 삽입
- 기존 행은
- 모든 변경 이력은
snapshots.customers_snapshot테이블에 누적 저장
구성요소 설명
5. Materializations — 저장 전략 선택
Materialization은 모델 실행 결과를 어떤 형태로 데이터베이스에 저장할지를 결정하는 방법입니다. dbt에서는 모델을 SQL로 작성하더라도, 그 결과를 View, Table, Incremental, Ephemeral 중 원하는 형태로 만들 수 있습니다. 즉, "쿼리 결과를 어떻게 보관할지"를 설정하는 단계입니다.
주요 Materialization 유형과 특징
예시 모델
- 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') }}- 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- 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예시 설명
- stg_orders
- 원본 데이터를 변환한 뷰(View) 생성 → 항상 최신 데이터 반영
- fct_orders
- 집계 결과를 테이블(Table)로 저장 → 실행 시 전체 재생성
- inc_orders
- 증분(Incremetal) 방식 → 새로 들어온 데이터만 추가 처리
구성요소 설명
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가 없어야 함예시2 - 커스텀 조건 테스트
-- tests/positive_order_amount.sql
select *
from {{ ref('orders') }} # 테스트 대상 모델 참조
where amount <= 0 # 주문 금액이 0 이하인 경우를 실패 조건으로 지정
#쿼리 결과가 한 행이라도 있으면 테스트 실패로 처리예시 설명
- 내장 테스트
- 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: "주문 총 금액(할인, 세금 포함)"예시2 - 소스(Source) 문서화
# models/staging/stg_sources.yml
# 원본 테이블의 역할과 생성 주기 등도 함께 기재 가능
version: 2
sources: # 외부/원본 데이터에 대한 설명을 추가
- name: raw
description: "원본 데이터베이스 스키마"
tables:
- name: orders
description: "주문 원본 테이블 (운영 DB에서 추출)"문서 생성과 계보 확인
dbt docs generate # 문서 파일 생성
dbt docs serve # 로컬 웹 서버로 문서 확인예시 설명
- 데이터 맥락(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;
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까지 이어지는 흐름을 이해하면, 단순 쿼리 관리 이상의 구조적이고 재사용 가능한 데이터 모델링을 설계할 수 있습니다.
다음 글에서는 이러한 모델과 파이프라인이 안정적으로 운영되도록 보장하는 데이터 품질 관리에 도움이 되는 테스트 기능을 자세히 알아보겠습니다.