dbt 2026 완벽 가이드: 데이터 변환, 테스트 전략, 면접 질문 총정리
dbt를 활용한 데이터 변환의 핵심 개념부터 실무까지, 레이어드 모델링, 인크리멘탈 전략, 테스트 방법론, 그리고 2026년 데이터 엔지니어링 면접에서 자주 출제되는 질문을 코드 예제와 함께 상세히 다룹니다.

dbt(data build tool)는 모던 데이터 웨어하우스 내에서 데이터 변환을 수행하는 표준 프레임워크로 자리 잡았으며, 2026년 현재 40,000개 이상의 기업이 프로덕션 환경에서 사용하고 있습니다. 이 튜토리얼에서는 dbt 데이터 변환의 핵심 메커니즘, 테스트 전략, 그리고 데이터 엔지니어링 면접에서 실제로 출제되는 질문들을 코드 예제와 함께 살펴봅니다.
dbt는 ELT에서 T(Transform)를 담당하는 도구입니다. SQL SELECT 문을 DDL(CREATE TABLE, CREATE VIEW, MERGE)로 컴파일하여 Snowflake, BigQuery, Redshift, Databricks 등의 웨어하우스에서 실행합니다. 버전 관리, 의존성 해결, 테스트, 문서화 기능이 기본으로 내장되어 있습니다.
레이어드 모델링: Staging, Intermediate, Marts
잘 구조화된 dbt 프로젝트는 변환 처리를 세 개의 레이어로 분리합니다. dbt 커뮤니티에서 널리 채택된 이 접근법은 각 모델의 단일 책임을 보장하고 디버깅을 용이하게 합니다.
Staging 모델은 원시 데이터에 가장 가까운 레이어에 위치합니다. 컬럼명 변경, 타입 캐스팅, 불필요한 행 필터링이 주된 역할이며, 조인이나 집계는 수행하지 않습니다.
-- models/staging/stg_orders.sql
WITH source AS (
SELECT * FROM {{ source('ecommerce', 'raw_orders') }}
)
SELECT
id AS order_id,
customer_id,
CAST(order_date AS DATE) AS order_date,
CAST(amount AS DECIMAL(10, 2)) AS order_amount,
LOWER(status) AS order_status
FROM source
WHERE id IS NOT NULLIntermediate 모델은 비즈니스 로직을 적용하는 레이어입니다. 조인, 집계, 윈도우 함수 등을 활용하며, ref()를 통해 Staging 모델을 참조함으로써 DAG에 의존성을 등록합니다.
-- models/intermediate/int_customer_orders.sql
WITH orders AS (
SELECT * FROM {{ ref('stg_orders') }}
),
customers AS (
SELECT * FROM {{ ref('stg_customers') }}
)
SELECT
c.customer_id,
c.customer_name,
COUNT(o.order_id) AS total_orders,
SUM(o.order_amount) AS lifetime_value,
MIN(o.order_date) AS first_order_date,
MAX(o.order_date) AS last_order_date
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.customer_id, c.customer_nameMarts는 최종 소비 레이어로, 대시보드와 분석가가 직접 쿼리하는 정리되고 문서화된 테이블을 제공합니다.
이 레이어 구조 덕분에 소스에 장애가 발생해도 Staging 레이어에만 영향을 미치며, 전체 파이프라인으로 확산되지 않습니다. 각 레이어는 독립적으로 테스트할 수 있습니다.
ref() 함수와 DAG 의존성 해결
ref()는 단순한 별칭이 아닙니다. {{ ref('stg_orders') }}를 호출하면 컴파일 시점에 정규화된 테이블명이 해결됨과 동시에, dbt의 DAG(방향 비순환 그래프)에 의존성 엣지가 등록됩니다. ref()가 없으면 dbt는 실행 순서를 결정할 수 없습니다.
흔히 저지르는 실수는 ref() 대신 테이블명을 직접 하드코딩하는 것입니다. 이는 의존성 추적을 깨뜨리고, 상위 의존 모델이 준비되기 전에 하위 모델이 실행될 수 있습니다.
-- 잘못된 예: 하드코딩된 참조, 의존성 추적 불가
SELECT * FROM analytics.stg_orders
-- 올바른 예: ref()로 의존성 등록
SELECT * FROM {{ ref('stg_orders') }}DAG는 dbt run --select stg_orders+와 같은 기능도 지원합니다. 이 명령은 지정된 모델과 그 하위의 모든 모델을 실행하며, 소스 스키마 변경 후 대상을 지정한 재빌드에 유용합니다.
매터리얼라이제이션: 적합한 스토리지 전략 선택
dbt는 네 가지 기본 매터리얼라이제이션을 제공하며, 접근 패턴과 데이터 규모에 따라 적절히 선택해야 합니다.
| 매터리얼라이제이션 | 스토리지 | 적합한 용도 | 트레이드오프 |
|----------------|---------|----------|----------|
| view | 스토리지 없음(읽기 시 연산) | 가벼운 변환, 소규모 데이터 | 대용량 데이터에서 읽기 속도 저하 |
| table | 매 실행마다 전체 테이블 재구축 | Mart 레이어, 빠른 읽기 | 전체 재구축, 높은 비용 |
| incremental | 신규 행만 추가/병합 | 대규모 팩트 테이블, 이벤트 스트림 | 복잡한 로직, unique_key 필요 |
| ephemeral | CTE로 인라인화, 실체화하지 않음 | 모델 간 공유되는 재사용 로직 | 직접 쿼리 불가 |
기본값은 view입니다. 모델의 config 블록 또는 dbt_project.yml에서 변경할 수 있습니다.
-- models/marts/fct_daily_revenue.sql
{{
config(
materialized='incremental',
unique_key='revenue_date',
incremental_strategy='merge'
)
}}
SELECT
DATE(order_date) AS revenue_date,
SUM(order_amount) AS daily_revenue,
COUNT(DISTINCT customer_id) AS unique_customers
FROM {{ ref('stg_orders') }}
WHERE order_status = 'completed'
{% if is_incremental() %}
AND order_date > (SELECT MAX(revenue_date) FROM {{ this }})
{% endif %}
GROUP BY DATE(order_date)is_incremental() 블록은 인크리멘탈 빌드 시에만 실행됩니다. 전체 리프레시(dbt run --full-refresh) 시에는 건너뛰어지고 테이블 전체가 재구축됩니다.
Data Engineering 면접 준비가 되셨나요?
인터랙티브 시뮬레이터, flashcards, 기술 테스트로 연습하세요.
각 레이어별 데이터 품질 테스트
dbt는 두 가지 유형의 테스트를 제공합니다. YAML에서 선언하는 제네릭 테스트와, 실패 시 행을 반환하는 독립 SQL 파일로 작성하는 싱귤러 테스트입니다.
제네릭 테스트는 구조적 제약 조건을 검증합니다.
# models/staging/_stg_models.yml
version: 2
models:
- name: stg_orders
columns:
- name: order_id
tests:
- unique # 주문 ID 중복 없음
- not_null # 모든 행에 주문 ID 존재
- name: order_status
tests:
- accepted_values:
values: ['completed', 'pending', 'cancelled', 'refunded']
- name: customer_id
tests:
- not_null
- relationships: # 참조 무결성 검사
to: ref('stg_customers')
field: customer_id싱귤러 테스트는 제네릭 테스트로 표현할 수 없는 비즈니스 규칙을 검증합니다.
-- tests/assert_revenue_never_negative.sql
-- 일일 수익이 음수인 행을 반환합니다(0행이 기대값)
SELECT
revenue_date,
daily_revenue
FROM {{ ref('fct_daily_revenue') }}
WHERE daily_revenue < 0유닛 테스트는 dbt 1.8에서 도입된 기능으로, 통제된 입력과 기대 출력으로 변환 로직을 검증합니다. 웨어하우스 연결이 필요 없으며 dbt 테스트 단계에서 직접 실행됩니다.
테스트 전략은 데이터 흐름을 따라 구성해야 합니다. 소스 레벨의 신선도 검사와 행 수 검증, Staging 레벨의 스키마 테스트(not_null, unique), Intermediate 레벨의 참조 무결성, Mart 레벨의 비즈니스 로직 어서션 순서로 적용하는 것이 권장됩니다.
dbt Core v1.10과 Fusion 엔진
dbt Core v1.10에서는 run 및 build 명령에 --sample 플래그가 도입되었습니다. 이 플래그는 ref()와 source()에 시간 기반 샘플링을 적용하여, 전체 빌드 비용 없이 데이터의 일부분으로 변환을 검증할 수 있게 합니다. 수십억 행의 팩트 테이블을 다루는 모델의 개발 반복 작업에 매우 유용합니다.
dbt Fusion 엔진은 Rust로 처음부터 재구축된 엔진으로, dbt Cloud의 Snowflake, BigQuery, Redshift, Databricks 환경에서 신규 프로젝트의 기본 엔진이 되었습니다. Fusion은 시맨틱 버저닝(2.0부터 시작)을 도입하고, 컴파일과 실행 양쪽에서 성능을 크게 향상시켰습니다.
2026년의 기타 주목할 만한 업데이트로는 중앙 집중식 메트릭 정의를 위한 Semantic Layer YAML 명세, 모델별 웨어하우스 컴퓨팅 비용을 추정하는 Cost Insights(베타), 그리고 정식 출시된 네이티브 프라이빗 패키지가 있습니다.
매크로와 Jinja를 활용한 재사용 가능한 로직
동일한 SQL 패턴이 여러 모델에서 반복될 경우, 매크로로 추출하는 것이 적절합니다. 매크로는 macros/ 디렉토리에 저장되는 Jinja 함수입니다.
-- macros/cents_to_dollars.sql
{% macro cents_to_dollars(column_name) %}
ROUND(CAST({{ column_name }} AS DECIMAL(10, 4)) / 100, 2)
{% endmacro %}모든 모델에서 호출할 수 있습니다.
-- models/staging/stg_payments.sql
SELECT
payment_id,
order_id,
{{ cents_to_dollars('amount_cents') }} AS amount_dollars,
payment_method
FROM {{ source('stripe', 'payments') }}이를 통해 코드베이스의 DRY 원칙을 유지할 수 있습니다. 변환 공식을 필요한 모든 모델에 복사하는 대안은 유지보수 비용 증가와 불일치의 원인이 됩니다.
데이터 엔지니어링 면접에서 실제로 출제되는 질문
2026년 데이터 엔지니어링 면접에서는 기초 지식을 넘어선 dbt 이해도를 평가하는 추세입니다. 다음은 모던 데이터 스택을 활용하는 기업의 채용 패턴에서 추출한, 지원자를 차별화하는 핵심 질문들입니다.
Q: 인크리멘탈 모델이 야간에 전체 테이블을 재처리했습니다. 원인은 무엇인가요?
가장 흔한 원인은 unique_key 컬럼에 NULL 값이 포함된 경우입니다. dbt가 NULL 키로 MERGE를 실행하면 모든 행에서 매칭이 실패하여 중복 삽입이 발생합니다. 두 번째 원인은 dbt run --full-refresh가 의도치 않게 실행된 경우입니다. 이 명령은 테이블을 처음부터 재구축합니다. 세 번째 원인은 is_incremental() 필터가 타겟 테이블에 아직 존재하지 않는 컬럼을 참조하는 경우(첫 실행과 이후 실행의 동작 차이)입니다. 디버깅은 target/compiled/ 디렉토리의 컴파일된 SQL 확인부터 시작합니다.
Q: 프로덕션 dbt 프로젝트에서 테스트를 어떻게 계층화해야 하나요?
소스 신선도 검사가 가장 먼저 실행되어야 합니다. 소스가 업데이트되지 않았다면 하위 모델은 오래된 데이터로 실행되어서는 안 됩니다. Staging 테스트에서는 스키마 제약 조건(기본 키의 unique + not_null, 허용값, 타입 캐스팅)을 검증합니다. Intermediate 테스트에서는 조인 간 참조 무결성을 확인합니다. Mart 테스트에서는 비즈니스 불변 조건(수익 >= 0, 활성 사용자 수 >= 유료 사용자 수, 부분의 합 = 전체)을 어서트합니다. 모든 테스트는 PR 시점에 dev 스키마에 대해 CI에서 실행하고, 배포 후에는 프로덕션 환경에서 알림과 함께 재실행합니다.
Q: 모델을 ephemeral로 해야 할 때와 view로 해야 할 때의 기준은 무엇인가요?
ephemeral 모델은 SQL을 CTE로 소비 모델에 인라인화합니다. 독립적으로 쿼리할 필요가 없는 재사용 로직에 적합합니다. view는 읽기 시점에 연산되며 쿼리 가능한 오브젝트로 존재합니다. 트레이드오프로, ephemeral 모델은 직접 테스트할 수 없고(어서션을 실행할 테이블이 존재하지 않음), 데이터 리니지 도구에도 표시되지 않습니다. 내부 헬퍼 로직에는 ephemeral을, 독립적인 테스트나 모니터링이 필요한 경우에는 view를 사용합니다.
Q: source()와 ref()의 차이를 설명해 주세요.
source()는 sources.yml 파일에 정의된 원시 테이블을 가리킵니다. 이 테이블들은 dbt가 관리하지 않는 대상입니다. ref()는 다른 dbt 모델을 가리킵니다. 두 함수 모두 DAG 의존성을 등록하지만, source()는 신선도 검사(dbt source freshness)도 활성화한다는 점이 ref()와의 차이입니다. 원시 테이블에는 source()를, 그 외에는 ref()를 사용하는 것은 선택이 아닌 필수이며, dbt가 관리 대상과 비관리 대상을 구분하는 방식입니다.
더 넓은 범위의 데이터 엔지니어링 면접 질문은 ETL vs ELT 파이프라인 아키텍처 등의 주제를 포함하여, SharpSkill의 dbt 기초와 dbt 고급 패턴 인터랙티브 연습 모듈에서 체계적으로 학습할 수 있습니다.
연습을 시작하세요!
면접 시뮬레이터와 기술 테스트로 지식을 테스트하세요.
결론
- dbt는 SQL SELECT 문을 DDL로 자동 컴파일하여 웨어하우스 내 원시 데이터를 변환합니다. Staging/Intermediate/Mart의 레이어 구조를 통해 각 모델은 단일 책임에 집중할 수 있습니다
ref()함수는 의존성 관리의 핵심으로, 테이블명 해결과 DAG 구축을 통한 실행 순서 제어를 담당합니다- 인크리멘탈 매터리얼라이제이션은 대규모 테이블의 비용을 절감하지만,
unique_key, NULL 값,is_incremental()필터의 세심한 처리가 필요합니다 - 테스트는 데이터 흐름에 따라 구성합니다. 소스 신선도 검사, Staging의 스키마 제약, Intermediate의 참조 무결성, Mart의 비즈니스 로직 어서션 순서가 권장됩니다
- dbt Core v1.10은 빠른 반복 작업을 위한
--sample플래그를 도입했으며, Fusion 엔진(Rust 기반, 버전 2.0)이 dbt Cloud의 기본 엔진이 되었습니다 - dbt 관련 면접 질문은 정의 암기가 아닌 실제 장애 디버깅(인크리멘탈 재처리, NULL 키, 오래된 소스)에 초점을 맞추고 있습니다. 컴파일된 SQL과 CI 파이프라인에 대한 실무 경험이 암기된 답변보다 중요합니다
연습을 시작하세요!
면접 시뮬레이터와 기술 테스트로 지식을 테스트하세요.
태그
공유
관련 기사

2026년 데이터 엔지니어링 면접 질문 상위 25개
2026년 데이터 엔지니어링 면접에서 가장 많이 출제되는 25가지 핵심 질문과 실무 중심의 답변을 제공합니다.

2026년 Apache Spark 4 완벽 가이드: 신규 기능, Structured Streaming, 면접 질문
Apache Spark 4의 핵심 신규 기능인 ANSI SQL 모드, VARIANT 데이터 타입, 실시간 스트리밍 모드, Spark Connect를 심층 분석합니다. 데이터 엔지니어링 면접을 위한 필수 질문과 답변도 함께 제공합니다.

2026 ETL vs ELT 완벽 비교: 데이터 파이프라인 아키텍처 설계 가이드
2026년 ETL과 ELT의 핵심 차이점, 비용 분석, 구현 패턴을 상세히 비교합니다. dbt, Airflow를 활용한 실전 데이터 파이프라인 설계 방법을 알아보세요.