(해시조인과 관련된 오라클힌트)해시조인은 두테이블 중 작은 테이블(Build Input, Driving Table)을 메모리에 조인키를 기반으로 해시테이블을 생성하고 해시테이블내에 행들을 위치시키기 위해 해시함수를 이용하며 나머지 테이블을 스캔하면서 메모리에 있는 해시테이블과 조인 조건을 만족하는 데이터를 찾는 조인이다. 중첩루프조인과 같이 조인시 발생하는 랜덤액세스에 대한 부하가 없는 조인방식이다. 관계형 데이터베이스에서 가장 비용이 많이 들어가는 조인방법으로 주로 작은 테이블과 큰 테이블의 조인 시 사용되며 , 드라이빙 조건과 상관없이 좋은 성능을 발휘할 수 있는 조인 방법이며 대체로 제일 빠르다.
2. 해시조인(HASH JOIN, USE_HASH)
해시조인은 두테이블 중 작은 테이블(Build Input, Driving Table)을 메모리에
조인키를 기반으로 해시테이블을 생성하고 해시테이블내에 행들을 위치시키기
위해 해시함수를 이용하며 나머지 테이블을 스캔하면서 메모리에 있는
해시테이블과 조인 조건을 만족하는 데이터를 찾는 조인이다.
중첩루프조인과 같이 조인시 발생하는 랜덤액세스에 대한 부하가 없는
조인방식이다.
관계형 데이터베이스에서 가장 비용이 많이 들어가는 조인방법으로 주로 작은
테이블과 큰 테이블의 조인 시 사용되며 , 드라이빙 조건과 상관없이 좋은
성능을 발휘할 수 있는 조인 방법이며 대체로 제일 빠르다.
3. HASH JOIN Example
• [MYEMP1_OLD테이블이 드라이비빙,
BUILD INPUT]
SELECT /*+ ORDERED USE_HASH(E2) */
EMPNO
FROM MYEMP1_OLD E1, MYEMP1 E2
WHERE E1.EMPNO = E2.EMPNO
4. 해시조인(HASH JOIN, USE_HASH)
해시 조인은 안티 조인과 병렬처리와 잘 맞고 범위검색이 아닌 동등 비교(Equi-Join,
where절에서 등호로 비교하는 경우)에 더 적합하다. 드라이빙이 되는 Build Input의
해시키 컬럼에 중복 값이 없어야 좋은 성능을 낸다.
해시테이블을 만드는 단계는 전체범위처리하며 Probe Input을 스캔하는 단계는
NL조인처럼 부분 범위 처리 가능 하다. 생성하는 비용이 수반됨으로 드라이빙
테이블(Build Input)이 작을 때 효과적이며 PGA 내부 Private SQL Area의 Runtime-
Area내부 SQL Work Area에 할당되는 Hash Area에 담길 정도로 작아야 한다.
소트 머지 조인하기에는 두 테이블이 너무 커 소트 부하가 심할 때 유리하며 수행
빈도가 낮고 쿼리 수행 시간이 오래 걸리는 대용량 테이블을 조인 할 때 좋으며
해시테이블은 단 하나의 쿼리를 위해 생성되고 조인이 끝나면 곧바로 소멸하는
자료구조이다.
USE_HASH : HASH JOIN을 하라는 힌트
NO_USE_HASH : HASH JON을 하지 말라는 힌트
5. ORDERED 힌트
ORDERED 힌트는 FROM 뒤에 기술되는 테이블의 순서대로 조인이 일어나도록
해주는 구문이며 대부분 단독으로는 사용되지 않고 USE_NL(중첩 루프 조인을 유도),
USE_MERGE(머지 소트 조인을 유도), USE_HASH(HASH 조인을 유도)등과 같이
사용된다.
USE_NL/USE_MERGE/USE_HASH등의 인자로 사용되는 테이블은 FROM절에서 두
번째로 나타나는 테이블 이어야 하는데 FROM절에서 처음 나타나는 테이블이
드라이빙 테이블(OUTER/DRIVING TABLE)이 되고 나중에 나타나는 테이블이
PROBED TABLE(INNER TABLE)이 된다.
6. HASH_JOIN, ORDERED 드라이빙 테이블 선정
-- ordered, use_hash 힌트를 이용한 조인시 드라이빙 테이블의 선정
-- 실습환경 오라클11g, MYEMP1은 1000만건, MYDEPT1은 7건
-- MYEMP1, MYDEPT1 테이블의 DEPTNO 칼럼에 인덱스 생성되어 있다.
-- 생성된 인덱스 확인
select a.index_name, a.column_name, b.visibility
from USER_IND_COLUMNS a, USER_INDEXES b
where a.table_name in ('MYEMP1', 'MYDEPT1')
and a.index_name = b.index_name
and a.column_name = 'DEPTNO'
order by a.index_name, a.column_name;
IDX_MYEMP1_DEPTNO DEPTNO VISIBLE
PK_MYDEPT1 DEPTNO VISIBLE
7. HASH_JOIN, ORDERED 드라이빙 테이블 선정
-- 힌트 사용안하고 했을 때는 중첩루프조인이 걸린다.
select e.ename, d.dname from mydept1 d, myemp1 e
where e.deptno = d.deptno
and e.deptno = '1';
-- 이번에는 NO_USE_NL을 이용하여 중첩루프 조인을
하지 말라고 하면 머지조인으로 실행을 한다.
select /*+ no_use_nl(e d) */ e.ename, d.dname
from mydept1 d, myemp1 e
where e.deptno = d.deptno
and e.deptno = '0';
8. HASH_JOIN, ORDERED 드라이빙 테이블 선정
-- 해시조인을 이용해 보자. use_hash의 인자는
비드라이빙(probe input)을 준다. ORDERED를
사용했으므로 MYDEPT1이 드라이빙(Build Input)
select /*+ ordered use_hash(e) */ e.ename, d.dname
from mydept1 d, myemp1 e
where e.deptno = d.deptno
and e.deptno = '0';
-- 해시조인인데 건수많은 myemp1이 드라이빙
테이블(Build Input), 좋은 모습이 아니며 느리다.
select /*+ ordered use_hash(d) */ e.ename, d.dname
from myemp1 e, mydept1 d
where e.deptno = d.deptno
and e.deptno = '0';
9. HASH_JOIN, ORDERED 드라이빙 테이블 선정
-- ORDERED 힌트를 사용하지 않고 USE_HASH에 인자를 2개, d, e 순서관계없이
작은 테이블을 Build Input으로
select /*+ use_hash(e d) */ e.ename, d.dname
from myemp1 e, mydept1 d
where e.deptno = d.deptno
and e.deptno = '0';
10. HASH_JOIN, ORDERED 드라이빙 테이블 선정
-- USE_HASH 인자로 하나만 주는 경우는 주의요망!
-- USE_HASH 인자는 비드라이빙(Probe Input)이 오는데,아래와 같이 d를 주었다는
이야기는 e 즉 큰테이블인 MYEMP1을 드라이빙(Build Input) 하라는 뜻이므로 한트를
무시해 버린다.(중첩루프걸림) 강제로 해시조인이 걸리게 하려면 강압적인 힌트
ORDERED와 같이 사용하면 된다. 해시조인 실행시 기본적으로 오라클은 작은 테이블을
메모리에 해시테이블로 구성되도록 한다.
select /*+ use_hash(d) */
e.ename, d.dname
from mydept1 d, myemp1 e
where e.deptno = d.deptno
and e.deptno = '0';
11. HASH_JOIN, ORDERED 드라이빙 테이블 선정
-- USE_HASH 인자로 하나만 주는 경우는 주의요망!
-- USE_HASH 인자는 비드라이빙(Probe Input)이 오는데,아래와 같이 큰테이블 e를
주었다는 이야기는 d 즉 작은테이블인 MYDEPT1을 드라이빙(Build Input) 하라는
뜻이므로 원하는대로 잘 돌아간다.
select /*+ use_hash(e) */
e.ename, d.dname
from mydept1 d, myemp1 e
where e.deptno = d.deptno
and e.deptno = '0';