← 학습 카테고리

Learn

dbt

11개 모듈 · 현재 2번째

dbt 모듈 2/11 dbt-learn-02

ref()·source()와 DAG, 프로젝트 설정 파일

50 dbt Interview Questions for Data Engineers (Real Answers, 2026) — 미상 (데이터 엔지니어링 커리어 블로그, 2026) Section 1: dbt Fundamentals, Q4-Q10 (pp.2-4)

이 모듈을 다 읽으면

  • ref()와 source()가 각각 무엇을 가리키고 DAG 구성에 어떻게 기여하는지 구분해 설명할 수 있다
  • materialization·설정값을 지정하는 세 위치(config 블록/YAML/dbt_project.yml)의 우선순위를 설명할 수 있다
  • dbt run과 dbt build의 차이를 근거로 각각을 언제 사용할지 판단할 수 있다

ref()는 다른 dbt 모델을 가리키며 동시에 DAG에 의존성을 등록하는 핵심 메커니즘이고, source()는 dbt가 관리하지 않는 원천 테이블을 가리키며 프레시니스 체크 같은 부가 기능을 제공한다. 프로젝트 설정은 모델 config 블록 > YAML 프로퍼티 파일 > dbt_project.yml 순으로 우선순위를 가지며, dbt_project.yml은 프로젝트 전역·폴더 단위 기본값을, dbt run은 모델만, dbt build는 모델·테스트·스냅샷·시드를 DAG 순서로 함께 실행한다.

ref()와 source() — DAG를 만드는 메커니즘

ref('model_name')은 다른 dbt 모델의 완전한 스키마.테이블명으로 해석되는 동시에, DAG(Directed Acyclic Graph)에 의존성을 등록한다. ref()를 쓰지 않고 테이블명을 하드코딩하면 dbt는 모델 B가 모델 A에 의존한다는 사실을 알 수 없어 실행 순서가 뒤바뀌거나 병렬로 실행돼 쿼리가 실패하거나 오래된 데이터를 참조하게 될 수 있다. ref()는 단순한 '별칭'이 아니라 dbt의 의존성 그래프 자체를 동작시키는 메커니즘이라는 점이 인터뷰에서 자주 확인하는 포인트다.

source()는 이와 대비된다. source('source_name', 'table_name')은 dbt가 관리하지 않는, EL 도구가 적재해 둔 원천 테이블을 가리킨다. YAML 파일에 소스를 정의해 두고 source()로 참조하며, ref()는 dbt가 관리하는 모델을, source()는 외부 테이블을 가리킨다는 것이 핵심 차이다. 소스를 정의하면 프레시니스 체크(freshness check)도 함께 활성화되는데, 이는 dbt가 변환을 시작하기도 전에 상류 데이터가 오래됐는지 미리 경고해 준다.

DAG는 프로젝트 전체의 모든 ref()·source() 호출로부터 구축되는 의존성 그래프이며, dbt는 이를 이용해 실행 순서를 정한다 — 상류 의존성이 없는 모델이 먼저 실행되고, 독립된 브랜치는 병렬로 처리된다.

핵심 포인트

  • ref()는 다른 dbt 모델을 가리키며 동시에 DAG 의존성을 등록하는 메커니즘이지 단순 별칭이 아니다
  • source()는 dbt가 관리하지 않는 원천 테이블을 가리키며, ref()는 dbt 모델을 가리킨다는 점이 핵심 차이다
  • 소스 정의는 프레시니스 체크를 함께 제공해 상류 데이터가 오래됐을 때 변환 전에 경고할 수 있게 한다
  • DAG는 프로젝트 전체의 ref()·source() 호출로 구축되며, 독립적인 모델은 병렬로 실행된다

설정 우선순위와 프로젝트 파일, run vs build

모델의 materialization 등 설정값은 세 곳에서 지정할 수 있고 우선순위가 있다: 모델 자체의 config 블록({{ config(materialized='incremental') }}) > YAML 프로퍼티 파일 > dbt_project.yml. 대부분 팀은 dbt_project.yml에서 폴더 단위 기본값(예: models/staging/ 아래는 전부 view)을 설정하고, 필요할 때만 모델 단위에서 override한다. SQL 파일 안의 config 블록이 항상 최종적으로 이긴다.

dbt_project.yml은 모든 dbt 프로젝트의 루트 설정 파일로, 프로젝트 이름·버전·프로필·디렉터리 경로, 그리고 폴더 단위 모델 설정(materialization, 스키마, 태그)을 선언한다. 모델별 세부 속성(컬럼 설명, 테스트)은 여기 몰아넣지 말고 models/ 디렉터리 안의 YAML 파일에 둬야 한다.

profile은 대상 환경(웨어하우스 종류, 호스트, 자격증명, 데이터베이스, 스키마)의 접속 정보를 정의하며, 로컬 머신의 ~/.dbt/profiles.yml에 저장돼 프로젝트 저장소와 분리된다 — 이 덕분에 자격증명이 Git에 커밋되지 않는다. 하나의 프로필은 dev, ci, prod 같은 여러 target을 가질 수 있고 dbt run --target prod로 전환한다. dbt Cloud에서는 프로필을 UI로 관리한다.

dbt run은 모델만 실행한다. dbt build는 모델·테스트·스냅샷·시드를 DAG 순서로 실행하며, 한 모델을 실행한 직후 바로 그 테스트를 실행하고 테스트를 통과해야만 다운스트림으로 진행한다. 이 때문에 dbt build가 테스트 실패를 조기에 잡아 하류로 전파되지 않게 막는 CI/CD의 더 안전한 기본값이다. 로컬에서 빠르게 반복 개발할 때는 dbt run, CI에서는 dbt build를 쓴다고 답하면 실전 경험이 드러난다.

참고: dbt-core 1.8(2024)부터는 unit test(단위 테스트)라는 새로운 테스트 유형도 추가됐다. 실제 웨어하우스 데이터 없이 모의(mock) 입력값으로 모델의 SQL 로직 자체만 검증할 수 있어, dbt build/dbt test 실행 시 함께 수행할 수 있다. 이 블로그가 쓰여진 시점 기준으로는 다루지 않는 내용이라 별도로 짚어둔다.

핵심 포인트

  • 설정 우선순위: 모델 config 블록 > YAML 프로퍼티 파일 > dbt_project.yml — SQL 파일 안 config가 항상 최종적으로 이긴다
  • dbt_project.yml은 프로젝트 전역·폴더 단위 기본값용이고, 모델별 세부 속성은 models/ 안 YAML에 둔다
  • profile은 ~/.dbt/profiles.yml에 저장돼 자격증명이 저장소와 분리되며, dbt Cloud는 이를 UI로 관리한다
  • dbt run은 모델만, dbt build는 모델·테스트·스냅샷·시드를 DAG 순서로 실행하며 테스트 실패 시 하류 전파를 막는다
  • dbt-core 1.8부터 웨어하우스 데이터 없이 모의 입력으로 SQL 로직만 검증하는 unit test가 추가됐다