4.3 해시조인
NL조인은 인덱스 이용한 조인 방식이므로 인덱스 구성에 따라 성능차이가 심하다.
인덱스를 아무리 완벽하게 구성하더라도 랜덤 I/O 떄문에 대량 데이터 처리에 불리하다.
소트 머지 조인은 양쪽 테이블 정렬하는 부담이 있다.
4.3.1 기본 메커니즘
해시 조인의 두 단계
- Build 단계 : 작은 쪽 테이블(Build Input)을 읽어 해시 테이블을 생성
- Probe 단계 : 큰 쪽 테이블(Probe Input)을 읽어 해시 테이블 탐색하면서 조인
해시 조인은 use_hash 힌트로 유도 한다.
select /*+ ordered use_hash(c) */
from 사원 e, 고객 c
where c.관리사원번호 = e.사원번호
and e.입사일자 >= '19950101'
and e.부서코드 = 'Z123'
and c.최종주문금액 >= 20000
- 빌드 단계: 조건에 해당하는 사원 데이터를 읽어 해시 테이블을 생성합니다. 사원번호를 해시 값으로 변환하여 사용합니다. 이 해시 테이블은 PGA 영역에 할당된 Hash Area에 저장됩니다. PGA에 저장할 수 없는 경우, Temp 테이블스페이스에 저장됩니다.
- 프로브 단계: 조건에 해당하는 고객 데이터를 하나씩 읽어서 미리 생성한 해시 테이블을 탐색합니다. 관리사원번호를 해시 함수에 입력하고, 반환된 값으로 해시 체인을 찾고 스캔하여 동일한 사원번호를 찾습니다.
4.3.2 해시 조인이 빠른 이유
조인 프로세싱 자체는 NL조인과 같지만, 해시 테이블을 PGA 영역에 할당하기 떄문에 래지 획득 과정 없이 PGA에서 빠르게 데이터를 탐색하고 조인한다.
대량데이터에서 소트 머지보다 일반적으로 해시 조인이 빠른 이유는
소트 머지 조인 - 양쪽 집합을 모두 정렬하여 PGA에 담는다. PGA는 큰 메모리 공간이 아니므로 Temp테이블스페이스(디스크) 쓰는 작업을 수반함.
해시 조인 - 양쪽 집합 중 한쪽을 읽어 해시 맵을 만드는 작업한다. 데이터가 큰 경우가 아니라면 Temp 테이블스페이스 작업이 일어나지 않음.
4.3.3 대용량 Build Input
두개의 테이블이 모두 대용량인 경우 인메모리 해시조인이 불가능한 상황에서DBMS는 분할 - 정복 방식으로 진행한다.
- 파티션 단계 : 조인하는 양쪽 집합의 조인 컬럼에 해시 함수를 적용하고, 반환된 해시 값에 따라 동적으로 파티셔닝 한다. 다만 디스크 Temp 공간에 저장해야 하므로 인메모리 해시 조인보다 성능이 많이 떨어진다.
- 조인 단계 : 파티션 단계를 완료하면 짝에 대해 하나씩 조인을 수행한다. 이떄 Build Input과 Probe Input이 독립적으로 결정 됨, (파티션 전 어느쪽이 작은 테이블인지 상관없이 각 짝별로 작은쪽을 Build Input으로 선택해 해시 테이블 생성)
4.3.4 해시 조인 실행계획
위쪽부터 데이터를 읽어 해시 테이블 생성 후 아래쪽 테이블에서 읽은 조인 키값으로 해시 테이블을 탐색하면서 조인한다.
0
1 0 HASH JOIN
2 1 TABLE ACCESS ....
3 2 INDEX ...
4 1 TABLE ACCESS ...
5 4 INDEX ...
해시 조인 실행계획을 제어 할때는 use_hash 힌트를 사용한다
select /*+ use_hash(c) */
e......
c......
from 사원 e, 고객 c
where c.관리사원번호 = e.사원번호
and e.입사일자 >= '19950101'
and e.부서코드 = 'Z123'
and c.최종주문금액 >= 20000
use_hash만 사용했으므로 Build Input을 옵티마이저가 선택하는데, 일반적으로 카디널리티가 작은 테이블을 선택한다.
Build Input을 직접 선택하고 싶다면
leading 또는 ordered 사용하면 됨. 힌트로 지시한 순서에 따라 가장 먼저 읽는 테이블을 Build Input 선택한다.
select /*+ leading(e) use_hash(c)
새 개 이상 테이블 해시 조인
select /*+ leading(t1, t2, t3) use_hash(t2) use_hash(t3) */
leading 힌트 첫 번쨰 파라미터로 지정한 테이블은 무조건 build input으로 선택된다.
T1이 선택된 Build Input을 T2로 변경하고 싶다면, swap_join_inputs 힌트 사용하면 된다.
select /*+ leading(t1, t2, t3) swap_join_inputs(t2) */
Bulid input으로 선택이 불가능한 상황에서는
Probe Input을 선택해주면 된다. no_swap_join_inputs
select /*+ leading(t1, t2, t3) no_swap_join_inputs(t3) */
4.3.5 조인 메소드 선택 기준
- 소량 데이터 조인 : NL 조인
- 대량 데이터 조인 : 해시 조인
- 대량 데이터 조인인데 해시조인이 불가능한 경우 (조인 조건식이 등치 조건이 아닐때) : 소트 머지 조인
소량과 대량의 기준은, NL 조인 기준으로 최적화 했는데 랜덤 액세스가 많아 성능을 낼 수 없다면 대량 데이터 조인에 해당.
- NL 조인과 해시 조인 성능이 같으면 NL 조인
- 해시 조인이 약간 더 빨라도 NL 조인
- NL 조인보다 해시 조인이 매우 빠른경우, 해시조인
3번에서 ‘매우 빠른 경우’는 대량 데이터 조인일 것이다.
NL조인을 우선적으로 선택해야하는 이유
- 인덱스는 영구적으로 유지하면서 다양한 쿼리를 위해 공유 및 재사용하는 자료구조
- 같은 쿼리를 수행하면, 해시 테이블도 100개 만들어진다. 해시는 cpu와 메모리 사용율이 높음
- 해시 맵을 만드는 과정에 여러 가지 래치 경합이 발생한다.
해시조인은 아래 세가지 조건이 만족하면 주로 사용한다.
- 수행 빈도가 낮고
- 쿼리 수행 시간이 오래 걸리는
- 대량데이터를 조인할때
배치, DW, OLAP성 쿼리 특징이다.
0.1초 걸리는(비효율X) NL 조인을 0.001초 단축하기 위해 해시 조인을 사용하는것은 적합하지 않다.