3. dbt 구성요소 살펴보기

·9분 읽기·
목차

지난 글에서는 SQLite 환경에서 dbt 프로젝트를 세팅하고, 첫 번째 모델을 만들어 실행해보았습니다.

이번 글에서는 dbt의 7대 핵심 구성요소를 하나씩 짚으며, 각각이 데이터 파이프라인에서 어떤 역할을 하는지, 그리고 서로 어떻게 맞물려 동작하는지를 살펴보겠습니다.


왜 구성요소를 이해해야 할까?

dbt는 단순히 “쿼리를 실행하는 도구”가 아니라, 데이터 변환 과정을 코드처럼 관리하고, 테스트·문서화·계보 추적까지 통합하는 데이터 모델링 프레임워크입니다.

구성요소의 의미를 이해하면, 팀 내에서 일관성 있는 설계·운영이 가능해집니다.


dbt의 7대 구성요소

구성요소역할실무 포인트
Models데이터 변환 로직의 최소 단위쿼리·의존성 관리
Sources원본 데이터 정의위치 고정·계보 추적
SeedsCSV 참조 데이터코드와 함께 버전 관리
Snapshots변경 이력 관리Slowly Changing Dimension
Materializations결과 저장 방식성능·운영 전략 선택
Tests데이터 품질 검증unique, not_null 등
Documentation모델·소스 문서화계보와 설명 자동화

1. Models — 변환 로직의 최소 단위

모델(Model)은 dbt에서 데이터 변환 로직의 최소 단위입니다. 한 모델은 하나의 SQL 파일이며, 이를 실행하면 테이블(Table) 또는 뷰(View)로 생성됩니다.

주요 특징

  • SQL로 작성되며 Jinja 템플릿({{ }}) 문법과 함께 사용 가능
  • 폴더 구조로 레이어 구분 가능 (staging, core, mart 등)
  • config를 통해 저장 방식, 태그, 결과물 이름 등을 제어 가능

예시 SQL

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_tstimestamp 형식으로 변환해 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 단위에서 바로 적용 가능
  • 변경 추적 가능 → 원본 스키마나 필드 변경 시 알림

예시 설정

yaml
# 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

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로 품질 검사 가능

구성요소 설명

구성 요소역할고려 사항
sources:원본 데이터 그룹 정의프로젝트별 논리 이름과 실제 DB 매핑 필요
tables:원본 테이블 목록모든 원본 테이블을 여기에 등록
columns:컬럼별 설명 및 테스트 정의컬럼 테스트는 데이터 품질 관리 핵심
source()SQL에서 source 참조YAML 정의와 반드시 이름·스펠링 일치

3. Seeds — CSV도 코드처럼 관리

Seed는 CSV 파일을 테이블로 로드하는 기능입니다. 원래 CSV를 DB에 넣으려면 별도의 로드 스크립트나 툴이 필요하지만, dbt에서는 CSV 파일을 data/ 폴더에 넣고 한 줄 명령으로 테이블로 변환할 수 있습니다.

주요 특징

  • CSV 파일도 Git에 버전 관리 가능
  • 배포 환경(dev/prod)에서 동일한 데이터 보장
  • 초기 코드/데이터 로딩, 기준값(코드 테이블) 관리에 유용

예시 CSV

sql
# data/country_codes.csv
country_code,country_name
KR,South Korea
US,United States
JP,Japan

예시 실행

bash
# seeds 로드
dbt seed

예시 SQL

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.csvdbt seed로 실행하면 DB에 country_codes 테이블 생성
  • 일관성 있는 기준 데이터 관리
    • 국가 코드, 상품 카테고리 코드, 상태 코드 등 변하지 않는 기준값을 Git에 저장
  • 모델에서 참조 가능
    • ref('country_codes')를 사용하여 다른 테이블과 조인

구성요소 설명

구성 요소역할고려 사항
data/seed CSV 저장 폴더파일명 = 생성될 테이블명
CSV 헤더컬럼명 정의SQL에서 그대로 사용
dbt seedCSV → 테이블 로드 명령실행 시 기존 데이터 덮어씀
ref()seed 참조 함수모델명과 동일한 이름 사용

4. Snapshots — 변경 이력 자동 관리

Snapshot은 테이블의 변경 이력(History)을 자동으로 관리하는 기능입니다. 예를 들어 고객의 주소, 주문 상태, 상품 가격처럼 시간이 지나면서 변하는 값을 "변경 전"과 "변경 후"를 모두 보관하고 싶을 때 사용합니다.

주요 특징

  • 변경 감지 로직(변경된 행만 식별)
  • 변경 시점 기록
  • 기존 행 보존이 필요하지만, dbt의 Snapshot은 이를 SQL 한 장과 설정만으로 해결합니다.

예시 설정

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 %}

예시 실행

bash
# Snapshot 실행
dbt snapshot

테이블 예시

customer_idemailaddressdbt_valid_fromdbt_valid_to
1001a@sample.comSeoul, Korea2024-01-01 00:00:002024-02-15 10:20:00
1001a@sample.comBusan, Korea2024-02-15 10:20:00null

예시 설명

  • 원본 테이블에서 고객 정보 조회
  • customer_id를 기준으로 기존 Snapshot 데이터와 비교
  • email 또는 address 컬럼 값이 변경되면,
    • 기존 행은 dbt_valid_to에 변경 시각을 기록
    • 새 행을 dbt_valid_from 시각과 함께 삽입
  • 모든 변경 이력은 snapshots.customers_snapshot 테이블에 누적 저장

구성요소 설명

구성 요소역할고려 사항
snapshots/Snapshot SQL 파일 저장 폴더models 폴더와 별도로 관리
config()Snapshot 동작 방식 정의strategyunique_key는 필수
strategy변경 감지 방식check(컬럼 비교) / timestamp(갱신 시각 기반)
check_cols변경 여부를 확인할 컬럼 목록민감 데이터만 지정하면 불필요한 변경 감지 방지
dbt snapshotSnapshot 실행 명령주기적으로 실행해야 이력 축적 가능

5. Materializations — 저장 전략 선택

Materialization은 모델 실행 결과를 어떤 형태로 데이터베이스에 저장할지를 결정하는 방법입니다. dbt에서는 모델을 SQL로 작성하더라도, 그 결과를 View, Table, Incremental, Ephemeral 중 원하는 형태로 만들 수 있습니다. 즉, "쿼리 결과를 어떻게 보관할지"를 설정하는 단계입니다.

주요 Materialization 유형과 특징

유형특징장점단점활용 예시
view쿼리 정의만 저장, 데이터는 즉시 조회항상 최신 데이터 반영조회 시 매번 쿼리 실행경량 변환, Staging 레이어
table쿼리 실행 결과를 물리 테이블로 저장빠른 조회 속도변경 시 전체 재생성 필요집계, 마트(Mart) 모델
incremental새 데이터만 추가/갱신대규모 데이터 처리에 효율적증분 조건 관리 필요이벤트 로그, Append-only 데이터
ephemeral물리 저장 없이 다른 모델에 인라인중간 계산 용도에 최적단독 조회 불가복잡한 파이프라인 내부 조인

예시 모델

  1. view
sql
-- models/stg_orders.sql
{{ config(materialized='view') }}
select
    order_id,
    customer_id,
    cast(order_ts as timestamp) as order_time
from {{ source('raw', 'orders') }}
  1. table
sql
-- 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
  1. incremental
sql
-- 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) 방식 → 새로 들어온 데이터만 추가 처리

구성요소 설명

구성 요소역할초보자 주의 포인트
config(materialized=...)Materialization 지정기본값은 view
ref()다른 모델 참조ref를 쓰면 실행 순서 자동 관리
is_incremental()증분 실행 시 True증분 조건을 명확히 작성해야 함
this현재 모델의 DB 객체 참조증분 비교 시 유용

6. Tests — 데이터 품질 보장

dbt의 Tests는 모델이 만든 결과가 기대하는 조건을 충족하는지 자동으로 검증하는 기능입니다. 데이터 변환이 아무리 복잡해도, 품질이 담보되지 않으면 신뢰할 수 없습니다. dbt는 SQL 기반으로 작성한 규칙을 실행해, 오류나 결측 데이터를 사전에 발견하도록 도와줍니다.

예시1 - 기본 테스트 (Not Null & Unique)

yaml
# 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 - 커스텀 조건 테스트

sql
-- 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 - 모델 및 컬럼 문서화

yaml
# 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) 문서화

yaml
# models/staging/stg_sources.yml
# 원본 테이블의 역할과 생성 주기 등도 함께 기재 가능
version: 2

sources: # 외부/원본 데이터에 대한 설명을 추가
  - name: raw
    description: "원본 데이터베이스 스키마"
    tables:
      - name: orders
        description: "주문 원본 테이블 (운영 DB에서 추출)"

문서 생성과 계보 확인

bash
dbt docs generate   # 문서 파일 생성
dbt docs serve      # 로컬 웹 서버로 문서 확인

예시 설명

  • 데이터 맥락(Context) 보존
    • 수개월 후에도 “이 컬럼이 왜 이렇게 계산됐는지” 이해 가능
  • 협업 속도 향상
    • 데이터 정의서를 별도로 작성·관리할 필요 없이, dbt 코드와 함께 버전 관리
  • 데이터 계보 추적
    • ETL 파이프라인을 블랙박스처럼 쓰지 않고, 데이터 흐름을 투명하게 공개

구성요소 간 연결 흐름

mermaid
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까지 이어지는 흐름을 이해하면, 단순 쿼리 관리 이상의 구조적이고 재사용 가능한 데이터 모델링을 설계할 수 있습니다.

다음 글에서는 이러한 모델과 파이프라인이 안정적으로 운영되도록 보장하는 데이터 품질 관리에 도움이 되는 테스트 기능을 자세히 알아보겠습니다.