변경 영향도: lineage 기반 리뷰, downstream dashboard 보호
모델 하나를 바꿨더니 대시보드가 10개 깨졌다
분석 데이터 플랫폼에서 가장 흔한 사고는 "작은 변경"이 예상치 못한 곳까지 파급될 때 발생한다. dim_customers에 컬럼을 추가하거나 필터를 바꾸면, 그 모델을 참조하는 mart 5개, 그 mart를 보는 BI 대시보드 10개, 심지어 외부 팀이 직접 쿼리하는 뷰까지 영향을 받는다.
Lineage(계보)는 이 의존 관계를 추적해서, 변경 전에 "무엇이 깨지는가"를 미리 알 수 있게 한다. 데이터 플랫폼 운영에서 lineage는 사후 디버깅 도구가 아니라 사전 변경 위험도 평가 도구다.
1. dbt Lineage의 구조
dbt는 모든 ref()와 source() 참조를 파싱해서 DAG(방향 비순환 그래프)를 자동으로 구축한다. 별도 설정 없이 ref()를 쓰는 것만으로 lineage가 생성된다.
2. dbt CLI로 lineage 탐색하기
2.1 선택자(selector) 문법
dbt의 --select / --exclude 는 lineage를 탐색하는 핵심 도구다.
# int_orders_enriched 기준으로 상위(upstream) 모든 모델 선택
dbt ls --select +int_orders_enriched
# int_orders_enriched 기준으로 하위(downstream) 모든 모델 선택
dbt ls --select int_orders_enriched+
# 1단계 상위만 선택 (숫자로 깊이 제한)
dbt ls --select 1+int_orders_enriched
# 변경된 모델과 그 하위 모델 전체
dbt ls --select state:modified+
# 특정 폴더 아래 변경된 모델과 하위
dbt ls --select state:modified+ --models marts/이 선택자들을 dbt test, dbt build에도 그대로 쓸 수 있다.
# 변경 모델 하위 전체 빌드 + 테스트
dbt build --select state:modified+2.2 dbt docs로 시각적 lineage 확인
dbt docs generate # 문서와 lineage 메타데이터 생성
dbt docs serve # 로컬에서 DAG 뷰어 열기dbt docs serve를 열면 특정 모델을 클릭했을 때 좌우로 lineage가 펼쳐지는 인터랙티브 DAG 뷰어를 볼 수 있다. 신규 엔지니어가 데이터 구조를 파악할 때도 유용하지만, 변경 전 영향도 파악이 가장 직접적인 사용 사례다.
3. 변경 유형별 위험도 분류
모든 변경이 같은 위험을 갖지는 않는다. 변경 유형과 위치(레이어)에 따라 위험도가 달라진다.
컬럼 삭제, 컬럼명 변경
grain 변경 (집계 단위 변경)
조인 조건 변경 (행 수 변화)
staging → mart 전체 영향 가능
컬럼 추가
필터 조건 변경
계산 로직 수정 (컬럼명 유지)
downstream 쿼리는 동작하지만
숫자가 달라질 수 있음
주석, 설명 수정
materialization 변경
파티션 컬럼 추가 (기존 컬럼 유지)
downstream에 영향 없음
4. 컬럼 레벨 lineage
테이블 레벨 lineage만으로는 부족하다. dim_customers.customer_tier가 어떤 소스 컬럼에서 왔는지, 그 컬럼을 어떤 BI 지표가 사용하는지 알아야 한다. 이것이 컬럼 레벨 lineage다.
dbt 자체는 컬럼 레벨 lineage를 직접 제공하지 않지만, 외부 도구들이 dbt의 매니페스트와 SQL을 파싱해서 컬럼 레벨 추적을 제공한다.
| 도구 | 컬럼 레벨 lineage | dbt 통합 | 비고 |
|---|---|---|---|
| dbt docs | 미지원 (테이블 레벨) | 기본 내장 | 무료 |
| Datafold | 지원 | dbt Cloud / Core | PR 내 lineage diff |
| Atlan | 지원 | 메타데이터 수집 | 현대 데이터스택 특화 |
| OpenLineage + Marquez | 지원 | Airflow 연동 | 오픈소스 |
| Elementary | 부분 지원 | dbt 패키지 | 무료 오픈소스 |
컬럼 레벨 lineage가 실제로 중요한 상황:
customer_tier컬럼 계산 로직 변경 시, 이 컬럼을 쓰는 BI 지표 목록 파악- GDPR 요청으로
email컬럼을 마스킹해야 할 때, 영향받는 모델 전체 파악 - 소스 컬럼명이 바뀔 때, downstream SQL 수정 범위 예측
5. 변경 전 영향도 리뷰 프로세스
5.1 PR 리뷰 단계에서의 lineage 체크
변경 전에 영향 범위를 파악하는 것이 핵심이다. PR 리뷰 체크리스트에 lineage 항목을 추가한다.
### Lineage 영향도 체크 (PR 리뷰 항목)
□ 변경 모델의 downstream 목록을 확인했는가?
→ dbt ls --select <model>+
□ Breaking 변경(컬럼 삭제, 컬럼명 변경, grain 변경)이 포함되어 있는가?
→ 있다면 downstream 팀에 사전 공지 필요
□ 수치(금액, 건수, 비율)에 영향을 주는 로직 변경인가?
→ 영향받는 대시보드 소유자에게 리뷰 요청
□ CI에서 dbt build --select state:modified+ 가 통과했는가?5.2 CI에서 변경 영향 자동 감지
# .github/workflows/dbt-ci.yml (핵심 부분)
- name: dbt build - changed models and downstream
run: |
dbt build \
--select state:modified+ \
--defer \
--state ./prod_artifacts
env:
DBT_TARGET: ci--defer --state를 쓰면 변경되지 않은 upstream 모델은 프로덕션 결과물을 참조한다. CI 환경에서 전체 파이프라인을 실행할 필요 없이 변경 영향 범위만 실행한다.
5.3 Datafold를 이용한 데이터 diff
코드 변경이 실제 데이터에 어떤 영향을 주는지 row-level로 비교하는 것이 Data Diff다.
# datafold CLI로 두 브랜치의 mart_orders 비교
datafold dbt --ci-config-id <id> \
--master-branch main \
--feature-branch feature/customer-tier-fix결과: "mart_orders 3.2% 행 변경, paid_amount 평균 1.7% 증가" 같은 정량적 요약이 PR 코멘트로 자동 게시된다. 대시보드 숫자가 왜 바뀌었는지 설명이 필요할 때 이 diff가 근거가 된다.
6. Downstream Dashboard 보호 전략
6.1 소비자 계약 (Consumer Contract)
mart 테이블은 BI 도구와 암묵적 계약을 맺고 있다. 컬럼명, 타입, grain이 바뀌면 그 계약이 깨진다. Deprecated 컬럼을 즉시 삭제하는 대신 단계적으로 제거하는 전략이 필요하다.
-- 컬럼 deprecation 예시: 이름을 바꿔야 할 때
select
order_id,
-- 새 컬럼명 (정식)
net_revenue,
-- 구 컬럼명 유지 (deprecated, 2026-09-01 삭제 예정)
net_revenue as revenue_net -- 마이그레이션 기간 동안 유지
from ...그리고 dbt 문서와 Slack 공지를 동시에 보낸다. 소비자가 마이그레이션할 시간(보통 2~4주)을 준 후 삭제한다.
6.2 Exposure — BI 소비자를 lineage에 등록
dbt의 exposures는 downstream 소비자(대시보드, ML 모델, API 등)를 lineage에 등록하는 기능이다. 이를 통해 "어떤 대시보드가 어떤 mart를 쓰는가"를 dbt 문서에서 볼 수 있다.
# models/exposures.yml
exposures:
- name: daily_revenue_dashboard
label: "매일 매출 현황 대시보드"
type: dashboard
maturity: high # high / medium / low — 영향도 우선순위
url: https://lookerstudio.google.com/reporting/xxxxxxxx
description: >
재무팀이 매일 확인하는 매출 집계 대시보드.
mart_daily_revenue와 mart_orders를 기반으로 함.
depends_on:
- ref('mart_daily_revenue')
- ref('mart_orders')
owner:
name: 재무팀
email: [email protected]
- name: customer_ltv_model
label: "고객 LTV 예측 ML 모델"
type: ml
maturity: medium
depends_on:
- ref('mart_customer_ltv')
owner:
name: ML팀
email: [email protected]Exposure를 등록하면:
dbt docs에서 "이 mart를 쓰는 대시보드"를 시각적으로 확인 가능dbt ls --select +exposure:daily_revenue_dashboard로 대시보드의 upstream 전체 선택 가능- 변경 리뷰 시 "maturity: high" exposure가 영향받는지 확인하는 체크리스트 구성 가능
6.3 소유자 알림 프로세스
Exposure의 owner 정보를 활용해 영향받는 소유자에게 자동으로 알림을 보낼 수 있다.
# 변경된 모델의 영향을 받는 exposure 목록 출력
dbt ls --select state:modified+exposure:* --output json \
| jq '.[] | select(.resource_type == "exposure") | {name, owner}'이 결과를 CI 파이프라인에서 Slack이나 이메일로 자동 발송하면, PR이 머지되기 전에 대시보드 소유자가 변경 내용을 인지할 수 있다.
7. 전체 변경 안전 절차
8. 실전 안티패턴
8.1 "mart를 직접 수정해서 배포"
mart 스키마를 변경하면서 downstream BI 팀에 공지하지 않으면, 대시보드가 실행 시점에 오류를 내기 시작한다. 재무팀이 월간 리포트를 만들다가 알게 되는 최악의 시나리오다.
해결: Breaking 변경이면 최소 1~2주 전 공지, Exposure에 owner 등록, PR 리뷰에 lineage 영향도 명시.
8.2 "stg_에서 로직 변경"
Staging 레이어는 소스 정제만 해야 한다는 원칙을 어기고 비즈니스 로직을 넣으면, 그 로직이 잘못됐을 때 모든 downstream이 영향을 받는다. Staging 변경의 파급 범위가 intermediate/mart 변경보다 훨씬 크다.
해결: 비즈니스 로직은 intermediate로. Staging 변경은 소스 컬럼명·타입 변경이 아닌 한 최소화.
8.3 "exposure 없이 BI 도구 연결"
dbt 프로젝트에 exposure가 없으면 "어떤 대시보드가 어떤 mart를 쓰는지" 추적이 불가능하다. 나중에 lineage를 넣으려면 Looker, Tableau, Redash 등에서 역방향으로 조사해야 한다.
해결: mart를 처음 만들 때 exposure도 함께 등록. 시작할 때는 완벽하지 않아도 되며 주요 대시보드부터 시작한다.
마무리
데이터 플랫폼이 커질수록 변경의 파급 범위를 미리 파악하는 능력이 운영의 핵심이 된다. dbt의 lineage DAG, 선택자 문법, exposure 기능은 이 파악을 코드 수준에서 가능하게 한다. 컬럼 레벨 lineage와 Data Diff 같은 외부 도구는 이를 더 정밀하게 만든다.
변경 전에 downstream 소유자를 알고, 변경 후에 대시보드를 확인하는 문화를 만드는 것이 기술 도구만큼 중요하다. lineage는 그 문화를 지원하는 기반 인프라다.
다음 편에서는 파티션, 클러스터링, materialization 선택이 쿼리 성능에 어떤 영향을 주는지, 그리고 aggregate table을 언제 써야 하는지를 다룬다.
References
- dbt Labs, "Getting started with data lineage": https://www.getdbt.com/blog/getting-started-with-data-lineage
- Dagster, "dbt Lineage in Action: 3 Use Cases, Challenges and Best Practices": https://dagster.io/guides/dbt-lineage-in-action-3-use-cases-challenges-and-best-practices
- Datafold, "dbt lineage: What it is, and why it's important": https://www.datafold.com/blog/dbt-lineage/
- Atlan, "How Data Lineage & Impact Analysis Work | 2026 Guide": https://atlan.com/know/data-lineage-impact-analysis/
- dbt Labs, "About the exposures property": https://docs.getdbt.com/reference/resource-properties/exposures
- dbt Labs, "Node selection syntax": https://docs.getdbt.com/reference/node-selection/syntax
- dbt Labs, "state: comparison method": https://docs.getdbt.com/reference/node-selection/methods#the-state-method
- Medium (Tech with Abhishek), "dbt and Data Lineage: End-to-End Visibility for Analytics Engineering (2025)": https://medium.com/tech-with-abhishek/dbt-and-data-lineage-end-to-end-visibility-for-analytics-engineering-2025-10c5822aee91