< 원본 쿼리 >
select /*+ ordered use_hash(c) */
e.사원번호, e.사원명, e.입사일자,
c.고객번호, c.고객명, c.전화번호, c.최종주문금액
from 사원 e, 고객 c
where c.관리사원번호 = e.관리사원번호
and e.입사일자 >= '19960101'
and e.부서코드 = 'Z123'
and c.최종주문금액 >= 2000
↓ 수행과정 풀이
1) Build 단계
- 아래의 조건에 해당하는 사원 데이터를 읽어 해시 테이블을 생성한다.
조인 컬럼인 사원번호를 해시 테이블 키 값으로 사용한다.
사원번호를 해시 함수에 입력해서 반환값으로 해시 체인을 찾고
그 해시 체인에 데이터를 연결한다.
해시 테이블은 PGA영역에 할당된 Hash Area에 저장한다(너무 크면 temp 테이블스페이스)
select 사원번호, 사원명, 입사일자
from 사원
where 입사일자 >= '19960101'
and 부서코드 = 'Z123'
2) Probe 단계
- 아래 조건에 해당하는 고객 데이터를 하나씩 읽어 앞서 생성한 해시 테이블을 탐색한다
관리사원번호를 해시 함수에 입력해서 반환된 값으로 해시 체인을 찾고
그 해시 체인을 스캔해서 값이 같은 사원번호를 찾는다
찾으면 성공 , 못찾으면 실패
select 고객번호, 고객명, 전화번호, 최종주문금액, 관리사원번호
from 고객
where 최종주문금액 >= 2000
3) Probe 단계에서 조인하는 과정
(조인하는 과정을 PL/SQL로 표현)
begin
for outer in (select 고객번호, 고객명, 전화번호, 최종주문금액, 관리사원번호
from 고객 where 최종주문금액 >= 20000)
loop -- outer 루프
for inner in (select 사원번호, 사원명, 입사일자
from PGA에_생성한_사원_해시맵
where 사원번호 = outer.관리사원번호)
loop -- inner 루프
dbms_output.put_line( ... );
end loop;
end loop;
end;
➕ 해시테이블에는 조인 키 값뿐만 아니라 SQL에 사용한 컬럼을 모두 저장한다.
해시 조인은 NL조인처럼 조인 과정에서 발생하는 랜덤 액세스 부하가 없고, 소트 머지 조인처럼 양쪽 집합을 미리 정렬하는 부하도 없다.
해시 테이블을 생성하는 비용이 수반되지만, 둘 중 작은 집합을 Build Input으로 선택하므로 대개는 부담이 크지 않다.
( Temp 테이블스페이스를 쓰게 되더라도 대량 데이터 조인할 때는 일반적으로 해시 조인이 가장 빠르다 )
➕ 인메모리 해시 조인 : Build Input이 PGA에 담길 때
조인 할 두 테이블 모두 대용량 테이블이어서 인메모리 해시조인이 불가능한 경우
⇒ 분할 · 정복 ( Divide & Conquer ) 방식으로 진행
➕ 소량과 대량의 기준
단순히 데이터의 많고 적음이 아니라, NL 조인 기준으로 최적화했는데도 랜덤 액세스가 많이 만족할만한 성능을 낼 수 없다면 대량 데이터 조인에 해당.
수행빈도가 매우 높은 쿼리