기본 메커니즘
- 둘 중 작은 집합(Build input)을 읽어 Hash Area에 해시 테이블을 생성하고,
반대쪽 큰 집합을 읽어 해시 테이블을 탐색하면서 조인하는 방식이다.
- 해시 조인은, NL 조인처럼 조인 과정에서 발생하는 Random 엑세스 부하가 없고
소트 조인처럼 조인 전에 미리 양쪽 집합을 정렬하는 부담도 없다.
(다만, 해시 테이블을 생성하는 비용이 수반된다.
따라서 Build Input이 작을 때라야 효과적이다.)
- Build Input이 Hash Area 크기를 초과한다면 디스크에 썼다가 다시 읽어 들이는 과정을
거치기 때문에 성능이 많이 저하된다.
- 해시 키 값으로 사용되는 컬럼에 중복값이 거의 없을 때라야 효과적이다.
- 해시 테이블을 만드는 단계는 전체범위처리가 불가피하지만 반대쪽 Probe Input을
스캔하는 단계는 NL 조인처럼 부분범위처리가 가능하다.
- 해시 조인은 래치 획득 과정 없이 PGA에서 빠르게 데이터를 탐색한다.
힌트를 이용한 조인 순서 및 Build Input 조정
- 테이블이 2개만 있을 시 ordered, leading 힌트와 use_hash 힌트만 가지고 build input 테이블
선택이 가능
- 테이블이 3개 이상일 시 swap_join_input 힌트를 통해서 Build input 테이블 순서 조절 가능
Build input이 Hash Area를 초과할 때 처리 방식
- Grace 해시 조인
파티션 단계
- 조인되는 양쪽 집합 모두 조인 컬럼에 해시 함수를 적용하고,
반환된 해시 값에 따라 동적으로 파티셔닝 실시
- 파티션 단계에서 양쪽 집합을 모두 읽어 디스크 상의 Temp 공간에 일단 저장해야 하므로
In-Memory 해시 조인보다 성능이 크게 떨어지게 된다.
조인 단계
- 파티션 단계가 완료되면 각 파티션 짝에 대해 하나씩 조인을 수행한다.
파티션하기 전 어느 쪽이 작은 테이블이었는지 상관없이 각 파티션 짝별로 작은 쪽
파티션을 Build Input으로 선택해 해시 테이블을 생성한다.
- 해시 테이블이 생성되고 나면 반대쪽 파티션 로우를 하나씩 읽으면서 해시 테이블을
탐색하며, 모든 파티션 짝에 대한 처리가 완료될 때까지 이런 과정을 반복한다.
- Hybrid 해시 조인
- 순서는 책에 있으나 크게 중요한 것인지 모르겠음 ( 다 쓰기 너무 길다...)
- 그래서 결국 중요한 것은 Grace 해시 조인과 비교해서 실제 조인에 성공할 만한 값들만
걸러네서 조인하는 것
- Recursive 해시 조인 (= Nested-loops 해시 조인)
- 디스크에 기록된 파티션 짝끼리 조인을 수행하려고 '작은 파티션'을 메모리에 로드하는
과정에서 또다시 가용 Hash Area를 초과하는 경우 추가 파티셔닝을 단계를 거치게 되는데,
이를 'Recursive 해시 조인'이라고 한다.
- Recursive 해시 조인을 'Multipass 해시 조인'이라고도 함
Onepass 해시 조인은 디스크 쓰기가 발생했지만 Multipass 오퍼레이션을 거치지 않은 경우
Optimal 해시 조인dms 디스크를 전혀 사용하지 않은 In-Memory 해시 조인
- 비트- 벡터 필터링
- 조인 성공 가능성이 없는 파티션 레코드는 아예 디스크에 기록되지 않게 하려는 것
- 조인 단계에서 실패할 수 밖에 없는 레코드를 디스크에 기록하지 않고 버린다면,
이를 다시 읽어 들여 조인하지 않아도 되므로 Grace Hash 조인의 성능을
크게 향상시킬 수 있다.
Build input 해시 키 값에 중복이 많을 때 발생하는 비효율
- 해시 알고리즘의 성능은 해시 충돌을 얼마나 최소화할 수 있느냐에 달렸다.
이를 방지하려면 그만큼 많은 해시 버킷을 할당해야 한다.
- 해시 버킷을 아무리 많이 할당하더라도 해시 테이블에 저장할 키 컬럼에 중복 값이 많다면
하나의 버킷에 많은 엔트리가 달릴 수 밖에 없다.
- 해시 조인에서 해시 키는 '=' 조인 컬러만으로 결정된다.
해시 조인 사용기준
● 해시 조인 성능을 좌우하는 두가지 포인트
- 한 쪽 테이블이 Hash Area에 담길 정도로 충분히 작아야 함
- Build Input 해시 키 컬럼에 중복 값이 거의 없어야 함
● 해시 조인을 효과적으로 사용하는 경우
- 조인 컬럼에 적당한 인덱스가 없어서 NL 조인이 비효율적일 때
- 조인 컬럼에 인덱스가 있더라도 NL 조인 드라이빙 집합에서 Inner 쪽 집합으로의
조인 엑세스량이 많아 Random 엑세스 부하가 심할 때
- 소트 머지 조인하기에는 두 테이블이 너무 커 소트 부하가 심할 때
( 우선 등치 조건과 sort가 필요 없다는 것은 기본일 듯 )
- 수행빈도가 낮고 쿼리 수행 시간이 오래 걸리는 대용량 테이블을 조인할 때
● 해시 조인의 남용 시 발생할 수 있는 문제들
- 수행빈도가 높은 쿼리에 해시 조인을 사용하면 CPU와 메모리 사용률을 크게 증가 시킴
- 래치 경합이 발생해 시스템 동시성을 떨어뜨리게 된다.
( SQL memory manager workare
, row cache objects , simulator hash latch, cache buffers chains )
- 단적으로 말해 OLTP 환경에서는 해시 조인을 쓰는 것은 가급적 자제해야 함