소트머지조인??
CREATE TABLE sorted_dept ( deptno primary key, dname )
ORGANIZATION INDEX
AS
SELECT deptno, dname FROM dept order by deptno
;
CREATE TABLE sorted_emp( empno , ename , deptno
, constraint sorted_emp_pk primary key(deptno, empno)
)
ORGANIZATION INDEX
AS
SELECT empno, ename, deptno FROM emp order by deptno
;
BEGIN
FOR outer IN (SELECT deptno, empno, rpad(ename, 10) ename FROM sorted_emp)
LOOOP -- outer 루프
FOR inner IN (SELECT dname FROM sorted_dept WHERE deptno = outer.deptno)
LOOP -- inner 루프
dbms_output.put_line(outer.empno||' : '||outer.ename||' : '||inner.dname);
END LOOP;
END LOOP;
END;
/
{*}Outer 테이블, Inner 테이블*
Sort Area에 미리 정렬해둔 데이터를 이용할 뿐, 실제조인과정은 NL조인과 동일하다고 하였다.
NL조인에서 Outer 테이블이 소트머지조인에서의 First테이블, Inner 테이블이 Second테이블로 명명되며, 이를 혼용해서 쓰기도한다.
SELECT /*+ ordered use_merge(e) */ d.deptno, d.dname, e.empno, e.ename
FROM dept d, emp e
WHERE d.deptno = e.deptno;
처리과정
1. Outer(=First)테이블인 dept를 deptno기준으로 정렬.
2. Inner(=Second)테이블인 emp를 deptno기준으로 정렬.
3. Sort Area에 정렬된 dept테이블을 스캔하면서, 정렬된 emp테이블과 조인.
소트머지 조인이 유용할 때
1. First 테이블에 소트 연산을 대체할 인덱스가 있을 때
2. 조인할 First 집합이 이미 정렬돼 있을 때
3. 조인 조건식이 등치(=)조건이 아닐 때
SQL> CREATE INDEX dept_idx ON dept(loc, deptno);
인덱스가 생성되었습니다.
SQL> CREATE INDEX emp_idx ON emp(job, deptno);
인덱스가 생성되었습니다.
SQL> SELECT /*+ ordered use_merge(e) */ *
2 FROM dept d, emp e
3 WHERE d.deptno = e.deptno
4 AND d.loc = 'CHICAGO'
5 AND e.job = 'SALESMAN'
6 ORDER BY e.deptno;
------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 59 | 5 (20)| 00:00:01 |
| 1 | MERGE JOIN | | 1 | 59 | 5 (20)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID | DEPT | 1 | 22 | 2 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | DEPT_IDX | 1 | | 1 (0)| 00:00:01 |
|* 4 | SORT JOIN | | 3 | 111 | 3 (34)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID| EMP | 3 | 111 | 2 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | EMP_IDX | 3 | | 1 (0)| 00:00:01 |
------------------------------------------------------------------------------------------
SELECT /*+ ordered use_merge(e) index(d dept_pk) */
d.dname, e.empno, e.ename
FROM dept d, emp e
WHERE e.deptno = d.deptno;
ex1) 부분범위처리 테스트를 위해 아래와 같이 실행 한다.
Step1) emp테이블을 100,000번 복제한 t_emp 테이블 생성
Step2) dept테이블과 조인 하기 위해 deptno 컬럼에 인덱스 생성
CREATE TABLE dept
AS
SELECT * FROM scott.dept;
CREATE TABLE t_emp
AS
SELECT * FROM scott.emp, (SELECT rownum no FROM dual CONNECT BY level <= 100000);
Case1) 작은 dept테이블이 First테이블이 되도록 소트머지조인
SELECT /*+ leading(d) use_merge(e) full(d) full(e) */ *
FROM t_emp e, dept d
WHERE d.deptno = e.deptno;
결과는 P243 참조
Case2) 큰 t_emp 테이블(인덱스가 있는)이 First테이블이 되도록 소트머지조인
SELECT /*+ ordered use_merge(d) full(d) index(e t_emp_idx) */ *
FROM t_emp e, dept d
WHERE d.deptno = e.deptno;
결과는 p244 참조
SELECT /*+ ordered use_merge(d) */ d.deptno, d.dname, e.avg_sal
FROMO (SELECT deptno, avg(sal) avg_sal FROM emp GROUP BY deptno) e
,dept d
WHERE e.deptno = d.deptno;
결과는 P244 참조
SELECT /*+ ordered use_merge(d) */ d.deptno, d.dname, e.avg_sal
FROM (SELECT deptno, avg(sal) avg_sal FROM emp GROUP BY deptno ORDER BY deptno) e
,dept d
WHERE e.deptno = d.deptno;
결과는 P245 참조
SELECT /*+ ordered use_merge(e) */ d.deptno, d.dname, e.avg_sal
FROM dept d
,(SELECT deptno, avg(sal) avg_sal FROM emp GROUP BY deptno ORDER BY deptno) e
WHERE e.deptno = d.deptno;
결과는 P246 참조