2. Spark 쿼리 튜닝
2.1 Query Profile 읽는 법
Databricks SQL 및 노트북의 Query Profile은 성능 병목을 시각적으로 보여줍니다. 병목 식별 우선순위2.2 Shuffle 최소화 전략
Shuffle은 네트워크를 통해 데이터를 재분배하는 가장 비싼 연산입니다. Broadcast Join (작은 테이블 조인)| 조인 전략 | 적용 조건 | Shuffle | 성능 |
|---|---|---|---|
| Broadcast Hash Join | 한쪽 < 100MB | 없음 | ★★★★★ |
| Sort Merge Join | 양쪽 모두 대용량 | 양쪽 Shuffle | ★★★☆☆ |
| Shuffle Hash Join | 한쪽 중간 크기 | 한쪽 Shuffle | ★★★★☆ |
2.3 Skew 처리
데이터 편향(Skew)은 특정 키에 데이터가 집중되어 일부 태스크만 과도하게 오래 걸리는 현상입니다.2.4 Spill to Disk 진단 및 해결
Spill은 메모리 부족으로 데이터를 디스크에 임시 저장하는 현상으로, 성능을 크게 저하시킵니다.| 진단 지표 | 확인 방법 | 임계값 |
|---|---|---|
| Spill (Memory) | Query Profile Stage Details | 0보다 크면 주의 |
| Spill (Disk) | Query Profile Stage Details | 0보다 크면 경고 |
| GC Time | Executor Metrics | 총 시간의 10% 초과 시 위험 |
2.5 Photon 활용 가이드
Photon은 Databricks의 벡터화된 쿼리 엔진으로, 특정 워크로드에서 큰 성능 향상을 제공합니다.| 워크로드 | Photon 효과 | 권장 여부 |
|---|---|---|
| SQL 집계/조인 (대용량) | 2~8x 빠름 | ✅ 강력 추천 |
| Delta MERGE/UPDATE/DELETE | 2~5x 빠름 | ✅ 강력 추천 |
| 넓은 테이블 (100+ 컬럼) 스캔 | 2~4x 빠름 | ✅ 추천 |
| Small File이 많은 테이블 | 2~3x 빠름 | ✅ 추천 |
| 단순 SELECT (< 2초) | 거의 효과 없음 | ⚠️ 불필요 |
| Python UDF 중심 로직 | 효과 없음 | ❌ Photon 미지원 |
| RDD API, Dataset API | 미지원 | ❌ 사용 불가 |
| 스트리밍 (Stateful) | 미지원 | ❌ Stateless만 가능 |
💡 비용 대비 효과: Photon 인스턴스는 DBU 단가가 약 2배이지만, 실행 시간이 3~5배 빨라져서 총 비용이 오히려 40~60% 절감 되는 경우가 많습니다.
3. AQE (Adaptive Query Execution) 심화
3.1 AQE 핵심 기능
AQE는 쿼리 실행 중 런타임 통계를 기반으로 실행 계획을 동적으로 최적화합니다.| AQE 기능 | 동작 | 효과 | 설정 |
|---|---|---|---|
| 동적 파티션 병합 | 작은 파티션을 런타임에 병합 | Small File → 적절한 크기 | coalescePartitions.enabled = true |
| 동적 조인 전환 | SortMerge → Broadcast 자동 전환 | Shuffle 제거 | localShuffleReader.enabled = true |
| Skew Join 처리 | 편향된 파티션 자동 분할 | 특정 태스크 병목 해소 | skewJoin.enabled = true |
| 동적 파티션 수 조정 | 실제 데이터 크기에 맞게 파티션 수 조정 | 과다/과소 파티션 방지 | advisoryPartitionSizeInBytes |
3.2 AQE와 Shuffle Partition 튜닝
참고
AQE 최대 활용 팁: spark.sql.shuffle.partitions 을 높게 설정(예: 2000)하고 AQE에게 병합을 맡기세요. AQE는 파티션을 나눌 수는 없고 병합만 가능합니다. 초기 파티션 수가 너무 적으면 AQE가 최적화할 여지가 없습니다.
4. 데이터 스큐 처리 전략 상세
4.1 Skew 진단 방법
4.2 Skew 해결 전략 비교
| 전략 | 적용 조건 | 구현 복잡도 | 효과 |
|---|---|---|---|
| AQE Skew Join | 대부분의 Skew | 자동 (설정만) | ★★★★☆ |
| NULL 키 사전 필터링 | NULL이 대량인 경우 | 낮음 | ★★★★★ |
| Salting | 극심한 Skew (AQE 부족) | 중간 | ★★★★★ |
| Repartition | 특정 키로 편향 | 낮음 | ★★★☆☆ |
| Broadcast Join | 한쪽이 작은 경우 | 낮음 | ★★★★★ |
4.3 Repartition 전략
5. Broadcast Join 임계값 튜닝
5.1 임계값 조정 가이드
| Executor 메모리 | 권장 Broadcast 임계값 | 비고 |
|---|---|---|
| 4GB 이하 | 10~30MB | 기본값 유지 |
| 4~16GB | 30~100MB | 중간 크기 디멘션 테이블 |
| 16~64GB | 100~500MB | 대부분의 디멘션 테이블 |
| 64GB 이상 | 500MB~1GB | 매우 큰 디멘션도 Broadcast |
주의 OOM 주의: Broadcast 임계값을 너무 크게 설정하면 Driver 또는 Executor에서 OutOfMemoryError가 발생할 수 있습니다. Broadcast되는 테이블은 각 Executor의 메모리에 복사되므로, Executor 메모리의 30%를 넘지 않도록 설정하세요.
6. Spark UI로 실행 계획 읽는 법
6.1 핵심 지표 해석
| Spark UI 탭 | 확인 항목 | 의미 |
|---|---|---|
| SQL 탭 | DAG Visualization | 쿼리의 물리적 실행 계획 |
| Stages 탭 | Input/Output Size | 단계별 데이터 이동량 |
| Tasks 탭 | Duration Distribution | 태스크별 실행 시간 분포 (Skew 확인) |
| Executors 탭 | GC Time, Spill | 리소스 사용 현황 |
6.2 실행 계획 읽기 순서
7. 자주 발생하는 성능 문제 Top 5 + 해결법
Top 1: SELECT * 사용
Top 2: 비효율적 조인 순서
Top 3: 데이터 타입 불일치
Top 4: 파티션 과다 (Over-partitioning)
Top 5: Collect/toPandas 대용량 데이터
참고 성능 문제 진단 순서: 1) Query Profile에서 가장 느린 단계 확인 → 2) Scan이 느리면 클러스터링/통계 확인 → 3) Shuffle이 크면 조인 전략 확인 → 4) Spill이 있으면 메모리/파티션 확인 → 5) Skew가 있으면 키 분포 확인.
참고 링크
- Databricks: AQE
- Databricks: Photon
- Databricks: Query Profile
- Databricks: Broadcast Join
- Databricks: Skew Join
- Spark: Adaptive Query Execution