데이터를 계속 쌓다 보면 성능이 떨어진다. 오늘은 Delta Lake 테이블을 빠르게 유지하는 방법과, 데이터를 안전하게 적재하는 패턴을 정리한다.
왜 최적화가 필요한가? — Small File Problem
데이터를 계속 적재하면 작은 파일이 쌓인다.
Delta 테이블 폴더
├── part-00001.parquet (1MB)
├── part-00002.parquet (500KB)
├── part-00003.parquet (200KB)
... 파일 수천 개
쿼리할 때 파일 수천 개를 하나씩 열어야 해서 느려진다. 이게 Small File Problem이다.
OPTIMIZE — 작은 파일 합치기
OPTIMIZE orders
흩어진 작은 파일들을 128MB짜리 큰 파일로 합친다.
Before: 파일 1000개 (각 1MB)
After: 파일 8개 (각 128MB)
ZORDER — 자주 쓰는 컬럼 기준으로 데이터 모으기
OPTIMIZE가 파일 개수를 줄인다면, ZORDER는 파일 안의 데이터 배치를 최적화한다.
OPTIMIZE orders ZORDER BY (customer_id)
WHERE customer_id = 1001 쿼리가 오면:
- ZORDER 없음: 전체 파일 스캔
- ZORDER 있음: 해당 customer_id가 모인 파일 몇 개만 스캔
단점: 새 데이터가 들어올 때마다 전체를 다시 재정렬해야 한다.
Day 1: OPTIMIZE ZORDER 실행 → 파일 10개 정렬 완료
Day 2: 새 데이터 유입 → 새 파일 50개 추가 (정렬 안 됨)
Day 2: OPTIMIZE ZORDER 다시 실행 → 기존 10개 + 새 50개 전체 재정렬
ZORDER는 전체 데이터 분포를 보고 정렬하는 알고리즘이라, 새 데이터가 끼어들면 기존 정렬이 깨져서 전부 다시 처리해야 한다.
Liquid Clustering — ZORDER의 진화 버전
ZORDER의 전체 재정렬 문제를 해결한 신규 기능(2023).
-- 테이블 생성 시 클러스터링 컬럼 지정
CREATE TABLE orders
CLUSTER BY (customer_id, order_date);
-- 이후 OPTIMIZE만 실행하면 자동 적용
OPTIMIZE orders
핵심 차이 — 점진적(incremental) 처리:
Day 1: OPTIMIZE → 파일 10개 클러스터링 완료 (완료 표시 저장)
Day 2: 새 데이터 → 새 파일 50개 추가
Day 2: OPTIMIZE → 새 파일 50개만 처리, 기존 10개는 건드리지 않음
Delta Lake가 "이 파일은 이미 클러스터링 됐음"을 기억하고 있어서 새 파일만 처리한다.
여기서 "Clustering"은 Spark 클러스터(서버 묶음)가 아니라, 비슷한 데이터를 같은 파일에 모으는 것을 의미한다.
| ZORDER | Liquid Clustering | |
|---|---|---|
| 처리 방식 | 전체 재정렬 | 새 파일만 점진적 처리 |
| 컬럼 변경 | 전체 재정렬 필요 | ALTER TABLE로 간단하게 |
| 신규 테이블 권장 | X | ✅ |
-- 클러스터링 컬럼 변경
ALTER TABLE orders CLUSTER BY (region, order_date)
VACUUM — 오래된 파일 삭제
Delta Lake는 UPDATE/DELETE를 해도 기존 파일을 바로 삭제하지 않는다. Time Travel을 지원하려면 이전 파일이 남아있어야 하기 때문이다.
VACUUM orders
기본값으로 7일 이상 된 파일을 삭제한다. 7일치 Time Travel은 보장된다.
-- 보존 기간 직접 지정
VACUUM orders RETAIN 720 HOURS -- 30일치 유지
주의: VACUUM 실행 후 삭제된 파일은 복구 불가능하다. 그 이전 버전으로 Time Travel도 불가능하다.
COPY INTO — 중복 없이 파일 적재
COPY INTO orders
FROM '/Workspace/Users/practice-user/data/'
FILEFORMAT = CSV
FORMAT_OPTIONS ('header' = 'true', 'inferSchema' = 'true')
핵심: 이미 적재한 파일은 자동으로 건너뛴다. 같은 명령을 10번 실행해도 데이터는 한 번만 들어간다. 이를 멱등성(idempotent) 이라고 한다.
| COPY INTO | Auto Loader | |
|---|---|---|
| 방식 | SQL 명령어 | 스트리밍 |
| 새 파일 감지 | 수동 실행 | 자동 감지 |
| 적합한 상황 | 배치, 소규모 | 대용량, 실시간 |
CTAS — 쿼리 결과로 테이블 만들기
CREATE OR REPLACE TABLE orders_kr
AS SELECT * FROM orders WHERE country = 'KR'
쿼리 결과가 바로 Delta 테이블이 된다. OR REPLACE를 붙이면 이미 테이블이 있어도 덮어쓴다.
Insert Overwrite — 데이터만 교체
INSERT OVERWRITE orders
SELECT * FROM orders_new
| CREATE OR REPLACE | INSERT OVERWRITE | |
|---|---|---|
| 스키마 변경 | 가능 (테이블 재생성) | 불가 (스키마 유지) |
| Time Travel | 이전 버전 사라짐 | 이전 버전 유지 |
| 용도 | 구조까지 바꿀 때 | 데이터만 교체할 때 |
INSERT OVERWRITE는 스키마를 유지하면서 데이터만 갈아끼우기 때문에 Time Travel로 이전 데이터 복구가 가능하다.
한 줄 정리
OPTIMIZE → 작은 파일을 128MB로 합치기
ZORDER → 자주 쓰는 컬럼 기준 정렬 (전체 재정렬)
Liquid Clustering → ZORDER 개선판, 새 파일만 점진적 처리
VACUUM → 7일 이상 된 파일 정리 (Time Travel 범위 축소)
COPY INTO → 중복 없이 파일 적재 (멱등성)
CTAS → 쿼리 결과로 테이블 생성
Insert Overwrite → 데이터만 교체, 스키마 유지, Time Travel 가능
✓ Day 1: Spark 기초
✓ Day 2: Delta Lake
✓ Day 3: Auto Loader
✓ Day 4: Structured Streaming
✓ Day 5: Delta Live Tables
✓ Day 6: Workflows
✓ Day 7: Architecture + Notebooks + Git Folders
✓ Day 8: DataFrameReader API + Views + JOIN + 집계 + Window Functions
✓ Day 9: Spark UDF + Higher Order Functions
✓ Day 10: Delta Lake 심화 (OPTIMIZE, ZORDER, Liquid Clustering, VACUUM, COPY INTO)
'공부를 하다 > Databricks' 카테고리의 다른 글
| Day 09. Spark UDF + Higher Order Functions (0) | 2026.08.24 |
|---|---|
| Day 08. DataFrameReader API + Views (0) | 2026.08.24 |
| Day 07. Databricks 아키텍처 + Notebooks + Git Folders (0) | 2026.08.24 |
| Day 06. Workflows — 파이프라인 자동화의 진화 (0) | 2026.08.01 |
| Day 05. Delta Live Tables — 파이프라인을 선언만 하면 알아서 실행되는 구조 (0) | 2026.08.01 |