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


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 내부에서 보통 이런 흐름을 탄다.
- SQL 파싱/검증
- 객체 존재 여부, 권한 보유 여부 확인
- 바이트코드(또는 내부 실행 표현)로 변환
- 플래닝 & 최적화
- 실행 순서 변경, 리팩터링(조인 순서, 필터 푸시다운 등) 결정
- 실행 & 결과 반환
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(데드 레코드)
- 오래된 레코드(데드 레코드)는 배큐밍으로 제거해야 할 수 있음
- 공간 확보 → 새 레코드 저장 가능
- 통계 정확도 개선 → 플래너 정확도 향상
- 나쁜 인덱스 정리 → 인덱스 성능 개선
- 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 구성 가능
- 재사용:
- 결과를 테이블로 커밋하거나 뷰 생성
- dbt 같은 도구로 모델/테스트/문서화를 체계화
Spark 네이티브 코딩 주의점
- 일찍, 자주 필터링
- 핵심 Spark API에 의존하고 동작 방식을 이해
- 부족하면 잘 관리된 공공 라이브러리 활용
- 좋은 코드는 “실질적으로 선언적”
- UDF 주의
- 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 객체
- 역할:
- 보안(접근 제어)
- 중복 제거된 현재 스냅샷 제공
- 공통 접근 패턴 표준화
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 기반 로우코드 도구도 워크플로 시각화에 도움
- “깔끔하고 성능 좋은 코드” 자체가 중요한 역량
'Data Engineering > BOOK' 카테고리의 다른 글
| [견고한 데이터 엔지니어링] CH10 보안과 개인정보보호 (0) | 2026.02.08 |
|---|---|
| [견고한 데이터 엔지니어링] CH9 5단계: 분석, 머신러닝 및 역 ETL을 위한 데이터 서빙 (0) | 2026.02.08 |
| [견고한 데이터 엔지니어링] CH7 3단계: 데이터 수집 (0) | 2026.01.31 |
| [견고한 데이터 엔지니어링] CH6 2단계: 데이터 저장 (0) | 2026.01.29 |
| [견고한 데이터 엔지니어링] CH5 1단계: 원천 시스템에서의 데이터 생성 (0) | 2026.01.11 |