새발블로그

[견고한 데이터 엔지니어링] CH8 4단계: 쿼리 모델링 및 데이터 변환 본문

Data Engineering/BOOK

[견고한 데이터 엔지니어링] CH8 4단계: 쿼리 모델링 및 데이터 변환

EUG 2026. 1. 31. 18:45

 

1) 쿼리(Query)

1-1. 쿼리란?

  • 쿼리: 데이터를 검색하거나, 그 데이터에 대한 작업을 수행하는 것
  • CRUD 관점에서 다양한 언어 계층이 존재

데이터 정의 언어(DDL)

  • 데이터 삽입 전에 필요한 DB 객체를 정의
  • CREATE, ALTER, DROP 등

데이터 조작 언어(DML)

  • 데이터 조회/삽입/갱신/삭제
  • SELECT, INSERT, UPDATE, DELETE, COPY, MERGE

데이터 제어 언어(DCL)

  • 누가 무엇에 접근 가능한지
  • GRANT, DENY, REVOKE

트랜잭션 제어 언어(TCL)

  • 트랜잭션 확정/되돌림
  • COMMIT, ROLLBACK

1-2. 쿼리 수명 주기(Query Lifecycle)

SQL이 실행될 때 DB 내부에서 보통 이런 흐름을 탄다.

  1. SQL 파싱/검증
    • 객체 존재 여부, 권한 보유 여부 확인
  2. 바이트코드(또는 내부 실행 표현)로 변환
  3. 플래닝 & 최적화
    • 실행 순서 변경, 리팩터링(조인 순서, 필터 푸시다운 등) 결정
  4. 실행 & 결과 반환

1-3. 쿼리 옵티마이저(Query Optimizer)

  • 쿼리를 효율적인 단계로 분해하고 순서를 재배치해 성능·비용 최적화
  • 조인 방식, 인덱스 활용, 스캔 크기, 기타 요소를 평가
  • 엔진마다 “같은 SQL이라도” 실행 방식이 미묘하게 다를 수 있다

1-4. 쿼리 성능 향상 포인트

(1) 가치는 ‘결합(Join)’에서 나온다

  • 테이블/파일 같은 단일 집합보다, 다른 집합과 결합할 때 가치가 커짐
  • 조인은 가장 흔한 결합 수단

(2) 선조인(Pre-join)과 구조 활용

  • 선조인: 미리 조인된 테이블/뷰를 만들어 반복 쿼리 비용을 줄임
  • 새로운 데이터 구조(배열/구조체 등) 활용도 성능·모델링에 영향

(3) 표준화된 스키마 유지

  • 분석/DS의 일반 활용 사례에 대해 “선조인된 표준 테이블”을 제공하면
  • 다운스트림 생산성이 크게 올라간다.

(4) 조인 폭발(Row Explosion) 주의

  • 다대다 매칭이 많으면 행이 폭발적으로 늘어날 수 있음
  • 초기에 폭발이 생기면 쿼리 실패/비용 폭증 가능
  • 조건절/조인 조건의 재정렬이 리소스 요구량을 줄이는 데 도움이 될 수 있음

(5) 쿼리 구조 가독성

  • 중첩 서브쿼리/임시테이블 대신 CTE(공통 테이블 표현식) 사용하면
  • 복잡한 쿼리를 읽기 쉽게 구성 가능
  • 중간 테이블은 보통 임시 테이블 형태로 생성되는 경우가 많음

1-5. 실행계획 기반 성능 파악(EXPLAIN)

  • EXPLAIN으로 쿼리 단계(실행 계획)를 확인할 수 있음
  • 모니터링해야 할 지표:
    • 디스크/메모리/네트워크 등 주요 리소스 사용량
    • 데이터 로딩 시간 vs 처리 시간
    • 실행 시간, 레코드 수, 스캔한 데이터 크기, 셔플 데이터량
    • 리소스 경합을 만드는 경쟁 쿼리
    • 동시 연결 수(한도 초과 시 사용자 영향)

1-6. 전체 테이블 스캔 방지 & 가지치기(Pruning)

  • 필요한 데이터만 쿼리해야 함
  • 스캔 양을 줄이는 핵심:
    • 열 지향: 필요한 컬럼만 선택
    • 파티션/클러스터링 키 활용해 가지치기
    • 행 지향: 인덱스 중심으로 최적화

주의:

  • 성능 민감 쿼리는 인덱스를 만들 수 있지만
  • 인덱스가 너무 많으면 쓰기/갱신 부담으로 성능이 오히려 저하될 수 있음

1-7. DB의 커밋 처리 방식(일관성/동시성)

  • 커밋: 레코드/테이블/객체의 생성·갱신·삭제 확정
  • 트랜잭션: 일관된 상태를 유지하기 위한 단위
  • ACID 준수 여부, dirty read 등 격리 수준이 영향을 준다.

엔진별 예시:

  • PostgreSQL: ACID 트랜잭션 적용 (단, 행 잠금 필요 → 단점)
  • BigQuery: 특정 시점 스냅샷에서 읽기만
    • 실행시간(1초/2시간)과 무관하게 같은 스냅샷 기반
    • 일관성 위해 “한 번에 하나의 쓰기”만 허용하는 특성이 있어
    • 쓰기 동시성이 낮고 도착 순서대로 큐잉될 수 있음
  • MongoDB: 가변적 일관성 옵션 제공
    • 높은 쓰기 성능 가능하지만 과부하 시 쓰기 폐기 등으로
    • 정확한 통계/정확성 요구가 높은 애플리케이션에 부적합할 수 있음

1-8. Vacuum / Dead Records(데드 레코드)

  • 오래된 레코드(데드 레코드)는 배큐밍으로 제거해야 할 수 있음
    1. 공간 확보 → 새 레코드 저장 가능
    2. 통계 정확도 개선 → 플래너 정확도 향상
    3. 나쁜 인덱스 정리 → 인덱스 성능 개선
  • Redshift는 디스크 구성을 바탕으로 자동 처리하는 특성이 있고,
  • PostgreSQL/MySQL 같은 RDBMS에서는 트랜잭션이 많으면 데드 레코드가 빠르게 쌓여 vacuum 중요성이 커진다.
  • 객체 스토리지는 공간이 곧 비용이라, 불필요한 데이터/버전이 누적되면 비용 문제가 생길 수 있음

1-9. 캐시된 쿼리 결과 활용

  • 같은 쿼리를 반복 실행하며 비용을 내기보다
  • 결과를 캐시/저장해서 즉시 재사용하는 게 효율적일 수 있음
  • 구체화 뷰(Materialized View)는 쿼리 캐싱의 대표 형태

2) 스트리밍 데이터에 대한 쿼리

2-1. 스트림 기본 쿼리 패턴

패스트 팔로워(Fast-follower) 접근

  • 운영 DB를 직접 분석 쿼리하면 운영 시스템이 느려지거나 충돌할 수 있음
  • CDC 기반으로 약간 지연된 통계/집계를 분석 DB에서 조회하면
  • 운영 영향 최소화 가능

단, 한계:

  • 배치 쿼리 패턴을 근본적으로 재고하지 않음
  • 이벤트 기반 “동적 트리거”에 약함

2-2. 카파 아키텍처(Kappa)

  • 이벤트를 테이블이 아니라 스트림으로 저장
  • 스트리밍 스토리지를 단순 버퍼가 아니라,
  • 과거 데이터까지 쿼리 가능한 저장소/DB처럼 취급
  • Kafka + ksql: 집계/통계/세션화 지원
  • 요구가 복잡해지면 Spark 등 외부 도구, Flink/Beam 같은 스트림 프로세서로 확장

2-3. 윈도/트리거/워터마크/늦게 도착한 데이터

  • 배치 세계: 외부 액터(크론/사람/대시보드)가 쿼리 실행을 “트리거”
  • 스트리밍 세계: 데이터 자체가 트리거가 되어 계산이 발생

윈도 유형:

  • 세션 윈도: 근접 이벤트를 그룹화, 비활성 구간 제거
    • “소급 세션화”처럼 세션 종료 후 일정 시간이 지나 처리 가능
  • 고정 시간 윈도: 고정 주기/고정 길이로 닫히며 처리
  • 슬라이딩 윈도: 겹칠 수 있는 고정 길이 윈도(예: 30초마다 60초 윈도 생성)

워터마크:

  • 늦게 도착한 데이터 판정 기준 타임스탬프 임계값
  • 워터마크보다 오래된 데이터는 late data로 처리

2-4. 스트림과 다른 데이터의 결합

  • 스트림 ↔ 테이블 조인(보강/enrichment)
    • 예: 서버리스 함수로 인메모리 DB에서 이벤트에 정보 추가 후 다른 스트림으로 출력
  • 스트림 간 조인
    • 지연시간 차이로 인해 버퍼/보존 간격이 필요
    • 보존 간격이 길수록 스토리지/리소스 사용 증가
    • 보존 기간이 지나면 버퍼 데이터는 제거됨

3) 데이터 모델링(Data Modeling)

3-1. 왜 모델링이 중요한가

  • 잘 구축된 아키텍처는 조직의 목표/비즈니스 논리를 반영해야 한다.
  • 모델은 “데이터를 비즈니스 성과로 변환”하는 데 초점이 있어야 함
  • 좋은 모델은 정의가 일관되고, 의사결정과 연결된다.

3-2. 데이터 모델이란?

  • 데이터가 실제 세계와 연관되는 방식
  • 데이터가 어떻게 구조화/표준화 되어야 하는지 반영

3-3. 개념적/논리적/물리적 모델

  • 개념적 모델: 비즈니스 논리·규칙 포함, ERD로 관계 시각화
  • 논리적 모델: 개념 모델이 실제로 구현되는 방법을 자세히
  • 물리적 모델: 구현(저장/인덱스/파티션 등) 방법 정의

핵심: 데이터 그레인(해상도)

  • 가능한 낮은 그레인으로 모델링하면
  • 다양한 집계를 만들 수 있다.

3-4. 정규화(Normalization)

  • 테이블/열 관계를 엄격히 제어해 중복 제거
  • 기본 키, 부분 종속성, 전이 종속성 관리

3-5. 배치 분석 데이터 모델링 기법

(1) 인먼(Inmon)

  • 원천 시스템과 분석 시스템 분리를 강조
  • 특징:
    • 주제 지향성 / 통합 / 비휘발성 / 시간변이성
  • 높은 정규화 통합 모델을 중심으로,
  • ETL이 DW → 다운스트림 데이터마트로 공급하는 흐름

(2) 킴벌(Kimball)

  • 상향식(Bottom-up)
  • 데이터마트가 “데이터웨어하우스 자체”가 될 수 있다는 관점
  • 핵심: 스타 스키마(팩트 + 차원)

팩트 테이블

  • 숫자/수량/이벤트 중심
  • 변경 불가, 추가 전용
  • 열은 적고 행이 많음
  • 가능한 최소 그레인 유지
  • 집계/파생은 팩트에 넣지 말고 downstream(마트/뷰)에서

차원 테이블

  • 이벤트의 맥락(내용/장소/시기) 제공
  • 폭이 넓고 행이 비교적 적은 형태
  • 비정규화로 중복 가능
  • 변경 추적은 SCD(천천히 변화하는 차원) 필요

스타 스키마

  • 조인 수 감소 → 성능 향상
  • BI 도구에서 직접 모델링/리포팅이 쉬움
  • “맞춰진 차원(Conformed Dimensions)”으로 여러 스타 스키마 재사용 가능

(3) 데이터 볼트(Data Vault)

  • 워크로드 데이터를 입력 전용 방식으로 적재
  • 구성:
    • 허브(Hub): 비즈니스 키 저장(중심 엔티티), 입력 전용
    • 링크(Link): 비즈니스 키 간 관계 추적(낮은 그레인 연결)
    • 위성(Satellite): 속성/컨텍스트, (허브 키 + 로드 날짜) 기반 키

(4) 와이드 비정규화 테이블

  • 요즘은 스토리지 비용이 저렴해지고, 중첩 데이터가 유행하며 완화됨
  • 장점: 단순 조회에 빠를 수 있음
  • 단점:
    • 비즈니스 로직 손실
    • 배열 요소 갱신 시 성능 저하

3-6. 스트리밍 데이터 모델링

  • 배치 → 스트리밍 전환, 온프레미스 → 클라우드 진화에 따라
  • 모델링도 함께 변해야 함

4) 변환(Transformation)

4-1. 변환이란?

  • 데이터 파싱/클렌징/조인/결합/집약
  • 쿼리 결과를 저장해서 “연산 부하 큰 작업을 한 번만” 수행하고 재사용 가능

개념 구분:

  • 쿼리: 원천에서 데이터 검색(필터/조인 로직 포함)
  • 변환: 그 결과를 목적에 맞게 “추가 가공”하여 데이터셋으로 만든다

4-2. 배치 변환

  • 개별 데이터 청크 단위로 실행
  • 고정 스케줄 기반

분산 조인(Distributed Join)

  • 논리적 조인을 작은 조인으로 분할해 클러스터에서 실행
  • 브로드캐스트 조인:
    • 큰 테이블 분산 + 작은 테이블 단일 노드 적재
    • 옵티마이저가 조인 재정렬을 중요하게 다룸
  • 셔플 해시 조인:
    • 테이블이 단일 노드에 들어갈 만큼 작지 않을 때 흔함
    • 셔플 비용이 커질 수 있음

ETL vs ELT

  • ELT: 원시 데이터 로드 후, 웨어하우스에서 클렌징/변환
  • “로드 시점에 변환하지 않고, 미래 시점에 변환 가능”이 핵심 장점

4-3. SQL 기반 vs 코드 기반 변환

SQL의 강점

  • 선언형 언어라 “최종 데이터 특성”을 규정하는 데 강함
  • CTE/스크립트/오케스트레이션으로 DAG 구성 가능
  • 재사용:
    1. 결과를 테이블로 커밋하거나 뷰 생성
    2. dbt 같은 도구로 모델/테스트/문서화를 체계화

Spark 네이티브 코딩 주의점

  1. 일찍, 자주 필터링
  2. 핵심 Spark API에 의존하고 동작 방식을 이해
    • 부족하면 잘 관리된 공공 라이브러리 활용
    • 좋은 코드는 “실질적으로 선언적”
  3. UDF 주의
  4. SQL 혼합 사용은 검토 필요

4-4. 갱신 패턴(Updates)과 삭제/재적재

입력 전용(append-only)

  • 이전 레코드를 변경/삭제하지 않고 새 레코드만 삽입
  • 최신 상태는 기본 키로 최신 레코드를 찾아야 함
  • → 단점: 조회 시 연산 비용 증가

삭제

  • 컬럼형 시스템/데이터 레이크에서 삭제는 입력보다 비용이 크다
  • 물리 삭제 vs 논리 삭제
  • “삭제 레코드 입력” 패턴(삭제 플래그를 가진 새 레코드 추가)

갱신 입력 & 병합(Merge)

  • 소스 레코드와 타깃을 키로 매칭해 갱신
  • 병합은 삭제까지 포함
  • 원래 행 기반 DB 중심 패턴이며,
    • 일부 레코드 변경/삭제만 있어도 파일 전체 재작성 + 포인터 교체
  • 파일 기반 시스템은 제자리 갱신이 안돼 “쓰기 시 복사”가 발생:

4-5. 스키마 갱신

  • 컬럼형 DB는 데이터 갱신이 어렵지만 스키마 갱신은 더 쉬울 수 있음
  • 클라우드 DW는 JSON 인코딩 타입 같은 유연한 타입도 지원
  • 자주 접근되는 데이터는 평면화 필드로 저장하는 전략이 흔함

4-6. 데이터 랭글링(Data Wrangling)

  • 지저분한 데이터를 유용하고 깨끗한 데이터로 변환
  • Spark 변환은 수집/조인/쓰기까지 코드 기반 DAG로 구현되는 경우가 많음

4-7. 비즈니스 로직과 파생 데이터

  • 파생 지표는 “저장된 다른 데이터에서 계산된 데이터”의 전형
  • 지표 버전이 늘어나기 쉬움(이익 전/후 수익 등)
  • ETL 스크립트는 DRY 위반이 되기 쉬움DW나 도구로 계산 부하 큰 작업을 수행하는 방향이 권장됨

->비즈니스 로직은 메트릭 계층에서 관리하고,

4-8. MapReduce와 이후

  • MapReduce는 빅데이터 시대 배치 변환의 핵심 패턴
    • map(블록 읽기) → shuffle(재분배) → reduce(집약)
  • 이후에는 “디스크/대역폭 저렴”이라는 전제 위에서
  • 초고속 쿼리를 위해 대량의 디스크를 투입하는 발상이 확산됨

5) 뷰/구체화 뷰/페더레이션/가상화

5-1. 뷰(View)

  • 다른 테이블을 참조하는 “쿼리 그 자체”인 DB 객체
  • 역할:
    1. 보안(접근 제어)
    2. 중복 제거된 현재 스냅샷 제공
    3. 공통 접근 패턴 표준화

5-2. 구체화 뷰(Materialized View)

  • 뷰의 일부/전부를 미리 연산하여 저장(조인 결과 포함 가능)

5-3. 구성 가능한 구체화 뷰

  • 예: Databricks Live Tables
  • 데이터 도착 시 갱신되며 비동기적으로 후속 테이블로 전달

5-4. 페더레이션 쿼리(Federated Query)

  • OLAP DB가 외부 소스(객체 스토리지/RDBMS 등)를 직접 조회
  • 예: Snowflake 외부 테이블(External Table)로 S3 조회 지원

5-5. 데이터 가상화(Data Virtualization)

  • 내부에 데이터를 저장하지 않고 처리/쿼리를 수행하는 시스템
  • 대표: Trino(Starburst/Presto)
  • 핵심 고려사항:
    • 외부 소스 의존성
    • 성능
    • 쿼리 푸시다운(가능한 많은 작업을 소스로 내려 보내기)
      • 가상화 계층 연산 부담↓
      • 네트워크 전송량↓
  • 조직 간 데이터 사일로를 완화하는 “장벽 추상화”로 쓰일 수 있고,
  • 데이터 메시 논의와도 연결됨

6) 스트리밍 변환과 처리

6-1. 기본 관점

  • 스트리밍은 “현재 뷰”를 동적으로 유지하는 느낌에 가깝다
  • 변환과 쿼리는 연속체(경계가 고정되지 않음)

6-2. 스트리밍 DAG

  • Kafka 같은 스트리밍 저장소 + Flink 같은 스트림 프로세서 조합으로 구성 가능
  • 잘못 만들면 “루브 골드버그 장치”처럼 복잡해질 수 있음

6-3. 마이크로배치 vs 진정한 스트리밍

  • 마이크로배치: 배치 프레임워크를 스트리밍처럼(2분→1초까지)
  • 진정한 스트리밍(Beam/Flink): 이벤트를 하나씩 처리
  • 윈도/트리거 기반으로 배치처럼 처리하며
  • 윈도 빈도/대기시간/지연 허용 등을 조정

결론적으로:

  • 도메인 지식 + 실무 테스트를 대체할 수 있는 건 없다.

7) 함께 일할 담당자

7-1. 업스트림 이해관계자

  • 비즈니스 정의 관리 담당자
  • 데이터 생성 시스템 관리 담당자
  • 알아야 할 것:
    • 데이터 원천이 무엇이고 어떻게 쓰이는지
    • 비즈니스 로직/정의
    • 모델 설계/갱신 과정 참여
    • 쿼리/변환이 원천 시스템에 주는 영향 최소화

7-2. 다운스트림 이해관계자

  • 변환 단계는 다운스트림에 직접 가치를 제공
  • 요구:
    • 성능: 최대한 빠르고 비용 효율적으로
    • 유용성: 품질/완전성 확보, 워크플로·데이터 제품에 통합 가능

8) 드러나지 않는 요소(Hidden Layers)

보안

  • 서로 다른 데이터 집합 간 결합이 많아질수록
  • 접근 권한/권한 경계 관리가 중요해짐

데이터 관리

  • 변환은 “새로운 데이터셋”을 만들어 관리 부담을 증가시킴
  • 기대치/명명 규칙/정의 정확성 필요
  • 시맨틱·메트릭 계층 고려
  • 데이터 계보(Lineage)는
    • 엔지니어(변환 이해)
    • 분석가(출처 파악)
    • 모두에게 필요
  • 법령 준수: 마스킹/난독화 등

데이터 옵스

  • 데이터/시스템 변경 이상 감지 및 알림
  • 품질 모니터링
  • 성능 모니터링: 대기열 길이, 동시성, 메모리/스토리지, 네트워크 지연, 디스크 I/O
  • 비용 관리 및 최적화

데이터 아키텍처

  • 데이터를 파괴하지 않고 변환 가능한 시스템 구축
  • 모델이 수집/스토리지와 어떻게 맞물리고,
  • 쿼리가 어떻게 수행되는지까지 포함해 설계

오케스트레이션

  • 단순 크론에서 시작하더라도
  • 복잡해지면 의존성 기반(워크플로) 접근이 필요

소프트웨어 엔지니어링

  • SQL/파이썬/JVM 언어 등 다양한 도구/언어가 섞임
  • 도구별 모범 사례 숙지 필요
  • dbt 같은 변환 도구 + CI/CD 파이프라인
  • GUI 기반 로우코드 도구도 워크플로 시각화에 도움
  • “깔끔하고 성능 좋은 코드” 자체가 중요한 역량