Bucketing과 Sort-Merge Bucket Join — 저장 시점에 미리 분산해 셔플을 없앤다
Spark History Server 및 Bucketing/Sort-Merge Bucket Join 공식 문서 종합 (웹 리서치, 2026) — Apache Spark 공식문서(monitoring), japila.pl The Internals of Spark SQL(Bucketing), SPARK-27865 japila.pl The Internals of Spark SQL — Bucketing, SPARK-27865
이 모듈을 다 읽으면
- bucketBy가 spark-learn-42의 브로드캐스트 조인과 다른 방식으로 셔플을 회피한다는 것을 설명할 수 있다
- 버킷 수가 다른 두 테이블 사이의 1:N 조인이 왜 예전엔 셔플이 필요했고 지금은 필요 없어졌는지 설명할 수 있다
spark-learn-42에서 다룬 여러 물리적 조인 전략(브로드캐스트가 작은 테이블을 복제해 셔플을 피하는 방식)과 대비해, Bucketing이 '쓰기 시점에 미리 같은 기준으로 분산해둬' 조인 시점의 셔플 자체를 없애는 또 다른 접근을 정리한다.
bucketBy — 쓰기 시점에 조인 키 기준으로 미리 분산해둔다
DataFrameWriter.bucketBy(버킷 수, 컬럼)로 테이블을 저장하면, 그 컬럼 값을 해시해 지정한 개수의 버킷으로 데이터를 미리 나눠 쓴다 — sortBy와 함께 쓰면 각 버킷 안에서 정렬까지 해둘 수 있다. spark-learn-42의 브로드캐스트 조인이 '작은 쪽을 복제해서' 셔플을 피한다면, bucketing은 '양쪽 모두를 조인 키 기준으로 미리 같은 방식으로 흩어놔서' 셔플을 피하는 정반대 접근이다 — 조인 시점엔 이미 같은 키가 같은 버킷(=같은 파티션 상당)에 있다는 걸 옵티마이저가 알고 있어 재분배가 필요 없다.
핵심 포인트
- bucketBy(버킷수, 컬럼)로 조인 키를 해시해 미리 버킷으로 분산 저장(sortBy로 버킷 내 정렬도 가능)
- 브로드캐스트 조인(작은 쪽 복제)과 정반대 접근 — 양쪽을 조인 키 기준으로 미리 같은 방식으로 분산해둬 조인 시점 재분배(셔플) 자체가 불필요
조건 — 같은 키, 같은 버킷 수여야 셔플이 완전히 사라진다
이 효과가 온전히 나려면 두 테이블이 같은 조인 키로, 같은 개수의 버킷으로 버킷팅돼 있어야 한다 — 조건이 안 맞으면(버킷 수가 다르면) 결국 재셔플이 일어난다. 다만 SPARK-27865로 도입된 기능 덕분에, 한쪽 버킷 수가 다른 쪽의 정수배(1:N 관계)이기만 하면 버킷 수가 서로 달라도 셔플 없는 sort-merge bucket join이 가능해졌다 — 예전엔 버킷 수가 정확히 같아야만 했던 제약이 완화된 것이다.
핵심 포인트
- 온전한 셔플 생략 조건: 같은 조인 키 + 같은 버킷 수 (안 맞으면 재셔플 발생)
- SPARK-27865: 버킷 수가 정수배(1:N) 관계이기만 하면 버킷 수가 달라도 셔플 없는 sort-merge bucket join 가능 — 예전의 '정확히 같아야' 제약 완화