[dbt] dbt 기반 데이터 모델링과 파이프라인 설계

1. 검토 배경

적재 파이프라인을 운영하다 보면 같은 사실이 두 곳에 기록되는 구조가 만들어지기 쉽다. 검증 규칙과 테이블 간 의존 관계가 코드(SQL, 잡 정의)에 한 번, 별도 관리 문서(위키, 스프레드시트)에 또 한 번 적히는 식이다. 두 기록은 시간이 지나면 어긋난다.

이 글에서는 데이터 품질 검증과 계보(lineage) 확인을 별도 관리 문서 없이 수행할 수 있는지 확인하기 위해, 변환 도구 dbt로 테스트 프로젝트를 구성해 실제 동작을 확인한 결과를 정리한다.

도구 도입을 결정하는 글이 아니다. 도구가 제공하는 범위와 제공하지 않는 범위를 실측으로 구분하는 것이 목적이다. 동작 확인은 dbt Core 테스트 프로젝트 기준이며, 본문의 스키마·테이블명(analytics 등)은 모두 예시 값이다.

확인하려는 항목은 네 가지다.

구분 확인하려는 것
동작 방식 모델 정의와 실행 명령 체계, 저장 형태별 차이, 증분 적재가 실제로 어떤 문장으로 수행되는지
품질 검증 검증 규칙 선언 방식, 검증 실패 시 후속 처리 차단 여부, 위반 행 보관 방식
메타데이터 의존 관계·물리 위치·검증 규칙을 별도 관리 없이 산출물에서 그대로 읽을 수 있는지
환경 분리 동일 코드로 개발 환경과 운영 환경을 분리할 수 있는지, 분리 기준이 무엇인지

2. 모델과 실행 구조

2.1 모델과 참조

dbt의 모델(model) 은 SELECT 문 하나를 담은 .sql 파일이며, 파일명이 곧 생성되는 테이블명이 된다. CREATE TABLE이나 INSERT를 직접 작성하지 않는다.

모델 간 참조는 물리 테이블명 대신 ref('모델명')으로 작성한다.

-- models/fct_orders.sql
select
    o.order_id,
    o.customer_id,
    o.ordered_at,
    p.amount
from  o
join  p on o.order_id = p.order_id

이 표기 하나에서 실행 순서, 부분 실행 범위, 영향 범위, 계보가 모두 도출된다. 참조 관계를 어딘가에 따로 적을 필요가 없다.

외부에서 적재된 테이블은 source('스키마', '테이블')로 참조한다. 도구가 생성하지 않고 존재를 전제로 읽기만 하는 대상이다. 반면 파일을 직접 올리는 seed 데이터는 도구가 생성하는 대상이므로 source가 아닌 ref로 참조한다.

2.2 실행 명령

명령 동작 실행 엔진 접속
dbt parse 프로젝트 파일만 읽어 의존 그래프와 메타데이터 산출물을 생성한다 불필요
dbt seed 파일 형태의 기준 데이터를 테이블로 적재한다 필요
dbt run 모델을 의존 순서대로 생성한다 필요
dbt test 선언된 검증 규칙을 실행한다 필요
dbt build 모델 생성과 검증을 의존 순서대로 번갈아 수행한다. 검증에 실패하면 그 하위 모델을 건너뛴다 필요

메타데이터만 필요한 경우 dbt parse만으로 충분하다. 실행 엔진을 기동하지 않으므로 소요 시간이 짧다.

2.3 저장 형태 (materialization)

모델이 물리적으로 어떻게 만들어지는지는 materialization 설정으로 정한다.

설정값 동작
view 테이블을 만들지 않고 조회 시점마다 원본 질의를 재실행한다
table 실행할 때마다 테이블을 전체 재생성한다
incremental 신규 구간만 반영한다. 대상 테이블이 없거나 전체 재생성 옵션을 주면 전체 생성으로 동작한다

2.4 증분 적재 동작

증분 조건은 is_incremental() 블록으로 작성한다.



select *
from 


대상 테이블이 없는 첫 실행에서는 이 블록이 컴파일 결과에서 제거되어 전체 생성이 된다. 두 번째 실행부터는 신규 구간만 임시 뷰로 만든 뒤 본체에 병합하는 두 단계로 수행된다. 병합 문장은 직접 작성하지 않고 incremental_strategy와 unique_key 설정에서 생성된다.

키가 지정된 병합 방식에서는 동일 키가 다시 들어와도 행이 중복되지 않고 기존 행이 갱신된다. 정정 데이터 재전송에 대응할 수 있는 구조다.

주의할 점이 하나 있다. 증분 모델은 이미 반영된 구간을 다시 읽지 않으므로, 모델 질의를 수정한 경우 전체 재생성(full refresh)을 한 번 수행해야 이전 구간에도 새 기준이 적용된다.


3. 데이터 품질 검증

3.1 검증 규칙 선언

검증 규칙은 코드가 아니라 모델과 같은 위치의 .yml 파일에 컬럼 단위로 선언한다. 테이블이 늘어나도 검증 코드를 수정하지 않고 선언만 추가한다.

# models/schema.yml
models:
  - name: fct_orders
    columns:
      - name: order_id
        tests:
          - not_null
          - unique
      - name: status
        tests:
          - accepted_values:
              values: ['placed', 'shipped', 'completed', 'returned']

기본 제공 규칙은 널 여부(not_null), 값 유일성(unique), 참조 무결성(relationships), 허용값 집합(accepted_values) 네 가지다. 각 규칙은 위반 행을 조회하는 질의로 변환되어, 결과가 한 건이라도 나오면 실패로 판정한다.

기본 규칙으로 표현되지 않는 조건은 질의 파일을 추가해 규칙으로 등록할 수 있다.

3.2 검증 실패 시 동작

dbt build는 모델 전체를 만든 뒤 검증을 일괄 수행하는 방식이 아니다. 모델 하나를 만들고 그 모델의 검증을 수행한 다음, 통과한 경우에만 하위 모델로 진행한다.

따라서 검증에 실패한 데이터는 하위 집계·마트로 전파되지 않는다. 검토 항목 중 후속 처리 차단 여부에 해당하는 확인 결과다.

다만 차단은 하위 모델 실행에 한정된다. 이미 생성이 끝난 해당 모델 자체를 되돌리지는 않으므로, 발행 전 차단까지 필요하면 저장소 측 별도 기능을 함께 사용해야 한다.

3.3 위반 행 보관

규칙에 store_failures 옵션을 지정하면 위반 행이 별도 스키마의 테이블로 저장된다. 실패 건수뿐 아니라 어떤 행이 걸렸는지 확인할 수 있다.

      - name: order_id
        tests:
          - unique:
              config:
                store_failures: true

테스트 환경에서는 기본 스키마 analytics 외에 위반 행 보관용 analytics_test_failures 스키마가 생성되는 것을 확인했다.


4. 산출 메타데이터

4.1 산출물 구성

산출물(artifacts) 은 dbt 명령을 실행할 때 target/ 디렉터리에 자동으로 생성되는 JSON 파일이다. 사람이 작성하는 문서가 아니라 실행의 부산물로 나온다.

산출물 생성 명령 담긴 정보
manifest.json dbt parse 모델 목록, 모델 간 의존 관계, 물리 스키마·테이블명, 저장 형태, 설명·태그, 검증 규칙
catalog.json dbt docs generate 저장소에서 조회한 실제 컬럼 타입

manifest.json은 프로젝트의 .sql과 .yml 파일을 파싱한 결과를 그대로 직렬화한 파일이다. 모델 하나가 JSON 노드 하나가 되고, ref()를 해석해 만든 의존 그래프가 parent_map과 child_map 형태로 함께 기록된다. .yml에 선언한 검증 규칙도 각 모델 노드에 포함된다.

이 과정은 저장소에 접속하지 않고 파일만 읽어 수행된다. 표에 있는 물리 스키마·테이블명도 저장소를 조회한 값이 아니라 4.3의 스키마 결정 규칙으로 계산한 값이다. 실제 컬럼 타입만 저장소 조회가 필요해 catalog.json으로 분리된다.

의존 그래프가 코드에서 자동으로 파생되므로 계보와 실행 순서를 별도 관리 문서에 다시 적을 필요가 없다. 모델 질의를 수정하면 산출물이 다시 생성되면서 관계 정보가 함께 갱신된다. 같은 사실을 두 곳에 기록하지 않으므로 코드와 문서가 어긋나는 문제가 발생하지 않는다.

4.2 확인된 한계

산출 메타데이터에는 한계도 분명하다.

  • 컬럼 목록과 설명은 .yml에 기재한 것만 담긴다. 기재하지 않은 컬럼은 산출물에 나타나지 않는다.
  • 컬럼 타입은 저장소를 조회하는 별도 명령(dbt docs generate)을 수행해야 채워진다. 수행하지 않으면 타입 정보가 비어 있는 상태가 된다.
  • dbt Core의 manifest.json만으로는 컬럼 단위 계보를 확인할 수 없다. 모델 간 의존 관계까지만 기록되며, 어떤 컬럼이 어떤 컬럼으로 이어지는지는 질의 구문을 별도로 분석해야 한다. dbt 플랫폼의 Enterprise Catalog는 별도의 컬럼 단위 계보 기능을 제공하므로 이 글에서 확인한 Core 산출물의 범위와 구분해야 한다.

4.3 스키마 결정 규칙

모델이 생성될 스키마는 접속 설정의 기본 스키마를 따른다. 모델 설정에 별도 스키마를 지정하면 대체가 아니라 기본스키마_지정값 형태로 결합된다. 기본 스키마가 analytics이고 지정값이 mart이면 analytics_mart가 된다.

테스트 환경에서 실제로 생성된 스키마는 기본 스키마, 실행 이력 보관용 스키마, 검증 위반 행 보관용 스키마 세 개였다. 환경 구분이 아니라 용도 구분으로 나뉜다.


5. 환경 분리 방식

dbt에 개발·운영 같은 고정된 환경 구분은 없다. profiles.yml에 접속 설정 묶음(target)을 이름 붙여 두고 실행 시점에 선택하는 방식이며, 이름과 의미는 사용자가 정한다.

# profiles.yml
example_project:
  target: dev            # 실행 시점에 --target 옵션으로 바꿀 수 있다
  outputs:
    dev:
      schema: analytics_dev
      threads: 4
    prod:
      schema: analytics
      threads: 8

접속 설정이 정하는 값은 접속 경로, 기본 스키마, 상위 저장소 구분, 병렬도다. 환경 구분 기준은 스키마를 나누는 방식과 상위 저장소를 나누는 방식 중 선택한다.

중요한 점은 모델 질의 어디에도 환경이 기재되지 않는다는 것이다. 물리 위치 해석은 접속 설정이 담당하므로, 동일한 질의가 환경별로 다른 대상을 가리킨다.

반대로 모델 질의 안에서 환경을 조건 분기하면 환경이 늘어날 때마다 전 모델을 수정해야 하고, 개발 환경 검증 결과가 운영 환경 동작을 보증하지 못하게 된다. 피해야 할 패턴이다.


6. 정리

실측으로 확인한 판정을 표로 정리한다.

항목 판정 근거
모델 간 의존 관계·계보 활용 가능 참조 표기 해석 결과가 메타데이터 산출물에 그대로 기록됨
물리 위치·저장 형태 활용 가능 스키마·테이블명과 저장 형태 설정이 산출물에 포함됨
품질 검증 규칙·결과 활용 가능 선언 기반 규칙 등록, 실패 시 하위 모델 차단, 위반 행 보관 동작 확인
컬럼 설명·타입 조건부 가능 설명은 기재분에 한정되고, 타입은 저장소 조회 명령을 별도 수행해야 채워짐
컬럼 단위 계보 별도 처리 필요 dbt Core의 manifest.json은 모델 단위 관계를 제공하며, 컬럼 관계는 추가 분석이 필요함
스케줄·수집·저장 범위 밖 실행 시점 결정, 외부 데이터 수집, 데이터 저장 기능을 제공하지 않음

핵심만 압축하면 다음과 같다.

  • 검토 목적이었던 품질 검증과 계보 확인은 별도 관리 문서 없이 도구 산출물만으로 수행 가능함을 확인했다.
  • 다만 dbt Core 산출물 기준으로 컬럼 단위 계보와 컬럼 타입은 추가 처리가 전제된다. manifest.json이 제공하는 관계는 모델 단위까지다.
  • 스케줄링과 수집은 dbt의 범위 밖이다. 기존 오케스트레이터와 수집 모듈이 그대로 담당해야 하며, 도구 도입이 이 영역을 대체하지 않는다.

참고 자료

Categories:

Updated:

Leave a comment