Hash Join을 고려해야 했던 이유
— 데이터는 적은데 왜 이렇게 느릴까?
1. 문제 상황
구조가 동일한 두 테이블 A, B가 있었다.
- 둘 다 문서정보 테이블과 INNER JOIN
- 인덱스는 유효하지 않음
- A는 데이터가 많음
- B는 데이터가 4건뿐
그런데 결과는 의외였다.
- A는 빠름
- B는 8초 소요
데이터가 적은 B가 훨씬 느렸다.
2. 원인: Join 방식의 차이
INNER JOIN은 논리적 조인이고
실제 물리적 실행 방식은 다음 중 하나가 선택된다.
- Nested Loop
- Hash Join
- Merge Join
옵티마이저는 비용 계산 후 자동으로 결정한다.
B가 느렸던 이유
B는 데이터가 적었기 때문에
옵티마이저가 Nested Loop를 선택했을 가능성이 크다.
Nested Loop는 다음과 같이 동작한다.
→ Inner 테이블 탐색
→ 반복
문제는 인덱스가 없을 경우이다.
탐색이 아니라 Scan이 발생한다.
즉,
4건 × 문서정보 전체 Scan
이 구조가 된다.
문서정보가 수백만 건이라면
4번 전체 스캔이 발생할 수 있다.
그래서 “데이터는 적은데 느린” 현상이 생긴다.
3. Hash Join을 적용했을 때
Hash Join은 이렇게 동작한다.
- 작은 테이블을 메모리에 올려 해시 생성
- 큰 테이블을 한 번만 스캔하며 매칭
즉,
문서정보를 1번만 읽는다
반복 Scan이 사라지기 때문에
속도가 폭발적으로 개선될 수 있다.
느린 SQL문에 대해 아래와 같이 수정해보자
SELECT ...
FROM B /*데이터 적고 느린 테이블*/
INNER HASH JOIN DOCUMENT_MASTER /* 데이터 많은 테이블(문서정보) */
ON ...
4. 데이터가 많아지면 어떻게 될까?
Nested Loop
시간 복잡도는 구조적으로:
O(N × M)
데이터가 증가하면
기하급수적으로 위험해진다.
특히 인덱스가 없으면 치명적이다.
Hash Join
시간 복잡도는:
O(N + M)
선형 증가한다.
다만 단점이 있다.
- 메모리 사용량 증가
- Hash Spill 발생 가능 (TempDB 사용)
- CPU 사용량 높음
즉, 폭발형은 아니지만
메모리 기반 리스크가 존재한다.
5. Nested Loop는 나쁜가?
Nested Loop는 상황에 따라 가장 빠른 조인 방식이다.
특히 다음과 같은 경우에는 Hash Join보다 훨씬 효율적이다.
1️⃣ 조인 대상이 매우 적을 때
Outer 테이블 결과가 몇 건 안 된다면
반복 자체가 거의 발생하지 않는다.
2️⃣ 조인 컬럼에 인덱스가 잘 설계되어 있을 때
Nested Loop + Index Seek는
필요한 데이터만 정확히 찾아간다.
이 경우 전체를 읽는 Hash Join보다 훨씬 빠르다.
3️⃣ OLTP 환경 (건별 조회 시스템)
회원 1명, 주문 1건 같은 조회는
대부분 Nested Loop가 최적이다.
6. 결론
✔ 인덱스가 없다면
대량 조인에서는
Hash Join이 구조적으로 더 안전하다.
특히,
데이터 수는 적지만
상대 테이블이 매우 크고
인덱스가 없는 경우
Nested Loop는 반복 Scan을 유발할 수 있다.
이때 Hash Join은 충분히 고려할 수 있는 선택지다.
하지만 Hash Join은 “응급처치”에 가깝다.
근본 해결:
- 조인 컬럼 인덱스 설계
- 통계 최신화
- 실행계획 확인
데이터가 적다고 항상 빠른 것은 아니다.
인덱스가 없는 조인에서는 Hash Join을 고려해볼 수 있다.
인덱스를 사용할 수 있다면 인덱스를 설계하는 것이 정답이고,
인덱스를 사용할 수 없는 상황에서 반복 Scan이 발생한다면
Hash Join을 고려해볼 수 있다.
'CS > SQL' 카테고리의 다른 글
| 결재 검증 SQL의 실행 흐름 개선 (EXISTS, Short-Circuit 적용) (0) | 2026.02.03 |
|---|---|
| MSSQL - 행마다 새로운 시퀀스 부여 (0) | 2026.01.28 |
| Index Merge (0) | 2026.01.06 |
| Covering Index (커버링 인덱스) (0) | 2026.01.06 |
| 인덱스 설계 사고방식 2 (0) | 2026.01.06 |