홈 › 대용량·배치 › 02 / 8

조인 방식: Nested Loop, Hash, Sort Merge 와 드라이빙 테이블

섹션 6진행 0 / 8

2. 핵심 원리

2.1 세 가지 조인 방식

조인은 두 표에서 조건이 맞는 행끼리 짝을 짓는 일입니다. DB 는 이를 세 가지 알고리즘 중 하나로 수행합니다.

방식 동작 유리한 경우
Nested Loop 바깥 행마다 안쪽 표를 찾음 바깥이 작고 안쪽 키에 인덱스
Hash 작은 쪽 해시 표 생성 후 큰 쪽 조회 대량 등가 조인, 인덱스 없음
Sort Merge 양쪽 정렬 후 병합 이미 정렬됨, 범위 조인

세 방식은 결과가 같습니다. 달라지는 것은 읽는 양, 메모리 사용, 첫 행이 나오는 시각입니다.

2.2 Nested Loop

바깥(드라이빙) 표를 한 행씩 읽고, 그 행의 조인 키로 안쪽 표를 찾습니다. 안쪽 표에 조인 키 인덱스가 있으면 행마다 인덱스로 몇 개만 읽으므로 빠릅니다. 인덱스가 없으면 바깥 행마다 안쪽 표를 처음부터 훑어 급격히 느려집니다.

  • 바깥 표가 작고 안쪽 조인 키에 인덱스가 있을 때 유리합니다.
  • 부분 범위 처리에 강합니다. 바깥에서 몇 행만 읽어도 결과가 바로 나가므로 첫 행이 빨리 나옵니다.
  • 바깥 행이 수백만 건이면 안쪽 탐색이 그만큼 반복되어 불리합니다.

2.3 Hash

두 단계로 진행합니다. 먼저 작은 쪽 표를 읽어 조인 키로 메모리에 해시 표를 만듭니다(빌드). 그다음 큰 쪽 표를 한 번 훑으며 각 행의 키로 해시 표를 찾습니다(프로브).

  • 조인 키의 같음(등가 조건)에만 쓸 수 있습니다. 해시 값은 대소 비교를 지원하지 않기 때문입니다.
  • 인덱스가 필요 없고 양쪽을 각각 한 번씩만 읽습니다. 대량 집계와 배치에 유리합니다.
  • 해시 표가 메모리에 다 안 들어가면 임시 공간(디스크)에 나눠 쓰므로 느려집니다.
  • 해시 표를 다 만든 뒤에야 결과가 나오므로 첫 행이 늦습니다.

2.4 Sort Merge

양쪽 표를 조인 키로 정렬한 다음 두 줄을 나란히 훑으며 병합합니다. 한 번 정렬된 뒤에는 두 표를 각각 한 번씩만 읽습니다.

  • 이미 정렬된 입력(인덱스 순서 등)이면 정렬 비용이 줄어듭니다.
  • 등가가 아닌 범위 조건에도 쓸 수 있습니다.
  • 정렬 비용이 크므로 그 밖의 경우에는 Hash 가 대체로 유리합니다.

2.5 드라이빙 표

조인에서 먼저 읽는 표를 드라이빙(바깥) 표라고 합니다. Nested Loop 에서는 이 선택이 곧 성능입니다. 바깥 행 수가 곧 안쪽 탐색 횟수이기 때문입니다.

옵티마이저는 통계로 드라이빙 표를 고르므로 FROM 에 쓴 순서와 무관합니다. 필요하면 힌트로 순서를 고정할 수 있습니다.

핵심

Nested Loop 가 빠르려면 조인 전에 거를 수 있는 조건이 드라이빙 표에 있어야 합니다. 바깥에서 행 수를 먼저 줄여야 안쪽 탐색 횟수가 줄어듭니다.

2.6 DB별 지원

DB Nested Loop Hash Sort Merge
Oracle · Tibero 있음 있음 있음
MySQL 기본(계열) 8.0.18 부터 없음
MSSQL Nested Loops Hash Match Merge Join

MySQL 은 Nested Loop 계열이 기본이고, 8.0.18 부터 Hash Join 이 들어왔습니다. 8.0.20 부터는 Block Nested Loop 를 완전히 대체합니다. Sort Merge 조인은 없습니다.

방식을 지정하는 힌트는 DB마다 다릅니다.

DB 방식 지정 순서 지정
Oracle USE_NL, USE_HASH, USE_MERGE LEADING
MSSQL OPTION (LOOP JOIN) 등 FORCE ORDER

힌트 상세는 대용량 04 레슨에서 다룹니다.