SQL> SELECT /*+ USE_NL( D E ) LEADING( E ) */ *
2 FROM SCOTT.DEPT D
3 , SCOTT.EMP E
4 WHERE E.DEPTNO(+) = D.DEPTNO;
...
15 개의 행이 선택되었습니다.
SQL> @XPLAN
Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | 록 | 0 | SELECT STATEMENT | 1 | 15 | 00:00:00.01 | 37 | ||
1 | NESTED LOOPS OUTER | 1 | 14 | 15 | 00:00:00.01 | 37 | ||||||||||
2 | TABLE ACCESS FULL | DEPT | 1 | 4 | 4 | 00:00:00.01 | 8 | |||||||||
| TABLE ACCESS FULL | EMP | 4 | 4 | 14 | 00:00:00.01 | 29 |
Predicate Information (identified by operation id):
3 - filter("E"."DEPTNO"="D"."DEPTNO")
{CODE}
SQL> DESC SCOTT.EMP;
이름 널? 유형
----------------------------------------------------------------------------------------------------------------- -------- -----
EMPNO NOT NULL NUMBER(4)
ENAME VARCHAR2(10)
JOB VARCHAR2(9)
MGR NUMBER(4)
HIREDATE DATE
SAL NUMBER(7,2)
COMM NUMBER(7,2)
DEPTNO NUMBER(2)
SQL> SELECT * FROM SCOTT.EMP ORDER BY EMPNO ASC;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- -------- ---------- ---------- ----------
7369 SMITH CLERK 7902 80/12/17 800 20
7499 ALLEN SALESMAN 7698 81/02/20 1600 300 30
7521 WARD SALESMAN 7698 81/02/22 1250 500 30
7566 JONES MANAGER 7839 81/04/02 2975 20
7654 MARTIN SALESMAN 7698 81/09/28 1250 1400 30
7698 BLAKE MANAGER 7839 81/05/01 2850 30
7782 CLARK MANAGER 7839 81/06/09 2450 10
7788 SCOTT ANALYST 7566 87/04/19 3000 20
7839 KING PRESIDENT 81/11/17 5000 10
7844 TURNER SALESMAN 7698 81/09/08 1500 0 30
7876 ADAMS CLERK 7788 87/05/23 1100 20
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- -------- ---------- ---------- ----------
7900 JAMES CLERK 7698 81/12/03 950 30
7902 FORD ANALYST 7566 81/12/03 3000 20
7934 MILLER CLERK 7782 82/01/23 1300 10
SQL> INSERT INTO SCOTT.EMP VALUES( '7935', 'MILLER', 'CLERK', '7782', '82/01/23', '1300', NULL, NULL );
1 개의 행이 만들어졌습니다.
SQL> COMMIT;
커밋이 완료되었습니다.
SQL> SELECT * FROM SCOTT.EMP ORDER BY EMPNO ASC;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- -------- ---------- ---------- ----------
7369 SMITH CLERK 7902 80/12/17 800 20
7499 ALLEN SALESMAN 7698 81/02/20 1600 300 30
7521 WARD SALESMAN 7698 81/02/22 1250 500 30
7566 JONES MANAGER 7839 81/04/02 2975 20
7654 MARTIN SALESMAN 7698 81/09/28 1250 1400 30
7698 BLAKE MANAGER 7839 81/05/01 2850 30
7782 CLARK MANAGER 7839 81/06/09 2450 10
7788 SCOTT ANALYST 7566 87/04/19 3000 20
7839 KING PRESIDENT 81/11/17 5000 10
7844 TURNER SALESMAN 7698 81/09/08 1500 0 30
7876 ADAMS CLERK 7788 87/05/23 1100 20
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- -------- ---------- ---------- ----------
7900 JAMES CLERK 7698 81/12/03 950 30
7902 FORD ANALYST 7566 81/12/03 3000 20
7934 MILLER CLERK 7782 82/01/23 1300 10
7935 MILLER CLERK 7782 82/01/23 1300 <== 이게 바로 유령부서임 ;;
15 개의 행이 선택되었습니다.
SQL> SELECT TABLE_NAME, CONSTRAINT_NAME, CONSTRAINT_TYPE FROM DBA_CONSTRAINTS
2 WHERE OWNER = 'SCOTT';
TABLE_NAME CONSTRAINT_NAME C
------------------------------ ------------------------------ -
EMP FK_DEPTNO R
DEPT PK_DEPT P
EMP PK_EMP P
소속 부서없이는 사원이 존재할 수 없다는 뜻이므로 테이블을 생성할 때 Not Null 제약을 두어야 한다.
SQL> SELECT /*+ USE_MERGE( D E ) LEADING( E ) */ *
2 FROM SCOTT.DEPT D
3 , SCOTT.EMP E
4 WHERE E.DEPTNO(+) = D.DEPTNO;
...
15 개의 행이 선택되었습니다.
SQL> @XPLAN
Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
0 | SELECT STATEMENT | 1 | 15 | 00:00:00.01 | 11 | |||||
1 | MERGE JOIN OUTER | 1 | 14 | 15 | 00:00:00.01 | 11 | ||||
2 | TABLE ACCESS BY INDEX ROWID | DEPT | 1 | 4 | 4 | 00:00:00.01 | 4 | |||
3 | INDEX FULL SCAN | PK_DEPT | 1 | 4 | 4 | 00:00:00.01 | 2 | |||
| SORT JOIN | 4 | 14 | 14 | 00:00:00.01 | 7 | 2048 | 2048 | 2048 (0) | |
5 | TABLE ACCESS FULL | EMP | 1 | 14 | 14 | 00:00:00.01 | 7 |
Predicate Information (identified by operation id):
4 - access("E"."DEPTNO"="D"."DEPTNO")
{CODE}
{CODE:SQL}
SQL> SELECT /*+ USE_HASH( D E ) LEADING( E ) */ *
2 FROM TEST_DEPT D
3 , TEST_EMP E
4 WHERE E.DEPTNO(+) = D.DEPTNO;
DEPTNO DNAME LOC EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
16 개의 행이 선택되었습니다.
SQL> @XPLAN
Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
0 | SELECT STATEMENT | 1 | 16 | 00:00:00.01 | 11 | |||||
| HASH JOIN OUTER | 1 | 14 | 16 | 00:00:00.01 | 11 | 1011K | 1011K | 743K (0) | |
2 | TABLE ACCESS FULL | TEST_DEPT | 1 | 5 | 5 | 00:00:00.01 | 7 | |||
3 | TABLE ACCESS FULL | TEST_EMP | 1 | 14 | 14 | 00:00:00.01 | 4 |
Predicate Information (identified by operation id):
1 - access("E"."DEPTNO"="D"."DEPTNO")
-- 역순
SQL> SELECT /*+ USE_HASH( D E ) LEADING( E ) */ *
2 FROM (SELECT IN_E.*, ROWNUM FROM TEST_DEPT IN_E ORDER BY DEPTNO DESC ) D
3 , TEST_EMP E
4 WHERE E.DEPTNO(+) = D.DEPTNO;
DEPTNO DNAME LOC ROWNUM EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
16 개의 행이 선택되었습니다.
SQL> @xplan
Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
0 | SELECT STATEMENT | 1 | 16 | 00:00:00.01 | 7 | |||||
| HASH JOIN OUTER | 1 | 14 | 16 | 00:00:00.01 | 7 | 972K | 972K | 751K (0) | |
2 | VIEW | 1 | 5 | 5 | 00:00:00.01 | 3 | ||||
3 | COUNT | 1 | 5 | 00:00:00.01 | 3 | |||||
4 | TABLE ACCESS BY INDEX ROWID | TEST_DEPT | 1 | 5 | 5 | 00:00:00.01 | 3 | |||
5 | INDEX FULL SCAN DESCENDING | TEST_DEPT_PK | 1 | 5 | 5 | 00:00:00.01 | 1 | |||
6 | TABLE ACCESS FULL | TEST_EMP | 1 | 14 | 14 | 00:00:00.01 | 4 |
Predicate Information (identified by operation id):
1 - access("E"."DEPTNO"="D"."DEPTNO")
{CODE}
{CODE:SQL}
SQL> SELECT /*+ USE_HASH( D E ) SWAP_JOIN_INPUTS( E ) */ *
2 FROM TEST_DEPT D
3 , TEST_EMP E
4 WHERE E.DEPTNO(+) = D.DEPTNO;
DEPTNO DNAME LOC EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
DEPTNO DNAME LOC EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
16 개의 행이 선택되었습니다.
SQL> @XPLAN
Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
0 | SELECT STATEMENT | 1 | 16 | 00:00:00.01 | 11 | |||||
| HASH JOIN RIGHT OUTER | 1 | 14 | 16 | 00:00:00.01 | 11 | 865K | 865K | 646K (0) | |
2 | TABLE ACCESS FULL | TEST_EMP | 1 | 14 | 14 | 00:00:00.01 | 3 | |||
3 | TABLE ACCESS FULL | TEST_DEPT | 1 | 5 | 5 | 00:00:00.01 | 8 |
Predicate Information (identified by operation id):
1 - access("E"."DEPTNO"="D"."DEPTNO")
-- 역순
SQL> SELECT /*+ USE_HASH( D E ) SWAP_JOIN_INPUTS( E ) */ *
2 FROM (SELECT IN_E.*, ROWNUM FROM TEST_DEPT IN_E ORDER BY DEPTNO DESC ) D
3 ,TEST_EMP E
4 WHERE E.DEPTNO(+) = D.DEPTNO;
DEPTNO DNAME LOC ROWNUM EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
DEPTNO DNAME LOC ROWNUM EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
16 개의 행이 선택되었습니다.
SQL> @XPLAN
Plan hash value: 663895112
Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | OMem | 1Mem | Used-Mem |
0 | SELECT STATEMENT | 1 | 16 | 00:00:00.01 | 7 | 1 | |||||
| HASH JOIN RIGHT OUTER | 1 | 14 | 16 | 00:00:00.01 | 7 | 1 | 865K | 865K | 700K (0) | |
2 | TABLE ACCESS FULL | TEST_EMP | 1 | 14 | 14 | 00:00:00.01 | 3 | 0 | |||
3 | VIEW | 1 | 5 | 5 | 00:00:00.01 | 4 | 1 | ||||
4 | COUNT | 1 | 5 | 00:00:00.01 | 4 | 1 | |||||
5 | TABLE ACCESS BY INDEX ROWID | TEST_DEPT | 1 | 5 | 5 | 00:00:00.01 | 4 | 1 | |||
6 | INDEX FULL SCAN DESCENDING | TEST_DEPT_PK | 1 | 5 | 5 | 00:00:00.01 | 2 | 1 |
Predicate Information (identified by operation id):
1 - access("E"."DEPTNO"="D"."DEPTNO")
{CODE}
{CODE:SQL}
SQL> SELECT /*+ ORDERED INDEX_FFS( E ) FULL( D ) FULL( E2 ) USE_HASH( E D E2) PARALLEL_INDEX( E ) PARALLEL( D ) PARALLEL( E2 ) / D., E2.*
2 FROM TEST_EMP E, TEST_DEPT D, TEST_EMP E2
3 WHERE E.DEPTNO = D.DEPTNO(+)
4 AND E.EMPNO = E2.EMPNO ;
DEPTNO DNAME LOC EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
DEPTNO DNAME LOC EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
14 개의 행이 선택되었습니다.
SQL> @XPLAN
Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
0 | SELECT STATEMENT | 1 | 14 | 00:00:00.03 | 9 | |||||
1 | PX COORDINATOR | 1 | 14 | 00:00:00.03 | 9 | |||||
2 | PX SEND QC (RANDOM) | :TQ10004 | 0 | 14 | 0 | 00:00:00.01 | 0 | |||
| HASH JOIN BUFFERED | 0 | 14 | 0 | 00:00:00.01 | 0 | 1155K | 1155K | 813K (0) | |
4 | PX RECEIVE | 0 | 14 | 0 | 00:00:00.01 | 0 | ||||
5 | PX SEND HASH | :TQ10002 | 0 | 14 | 0 | 00:00:00.01 | 0 | |||
| HASH JOIN OUTER BUFFERED | 0 | 14 | 0 | 00:00:00.01 | 0 | 1524K | 1524K | 566K (0) | |
7 | PX RECEIVE | 0 | 14 | 0 | 00:00:00.01 | 0 | ||||
8 | PX SEND HASH | :TQ10000 | 0 | 14 | 0 | 00:00:00.01 | 0 | |||
9 | PX BLOCK ITERATOR | 0 | 14 | 0 | 00:00:00.01 | 0 | ||||
| INDEX FAST FULL SCAN | TEST_EMP_PK | 0 | 14 | 0 | 00:00:00.01 | 0 | |||
11 | PX RECEIVE | 0 | 5 | 0 | 00:00:00.01 | 0 | ||||
12 | PX SEND HASH | :TQ10001 | 0 | 5 | 0 | 00:00:00.01 | 0 | |||
13 | PX BLOCK ITERATOR | 0 | 5 | 0 | 00:00:00.01 | 0 | ||||
| TABLE ACCESS FULL | TEST_DEPT | 0 | 5 | 0 | 00:00:00.01 | 0 | |||
15 | PX RECEIVE | 0 | 14 | 0 | 00:00:00.01 | 0 | ||||
16 | PX SEND HASH | :TQ10003 | 0 | 14 | 0 | 00:00:00.01 | 0 | |||
17 | PX BLOCK ITERATOR | 0 | 14 | 0 | 00:00:00.01 | 0 | ||||
| TABLE ACCESS FULL | TEST_EMP | 0 | 14 | 0 | 00:00:00.01 | 0 |
Predicate Information (identified by operation id):
3 - access("E"."EMPNO"="E2"."EMPNO")
6 - access("E"."DEPTNO"="D"."DEPTNO")
10 - access(:Z>=:Z AND :Z<=:Z)
14 - access(:Z>=:Z AND :Z<=:Z)
18 - access(:Z>=:Z AND :Z<=:Z)
{CODE}
SQL> EXEC DBMS_RANDOM.SEED( 150 ) ;
PL/SQL 처리가 정상적으로 완료되었습니다.
SQL> CREATE TABLE 입금 AS
2 SELECT ROWNUM 일련번호
3 , ROUND(DBMS_RANDOM.VALUE(1, 20)) 고객ID
4 , ROUND(DBMS_RANDOM.VALUE(1000, 1000000), -2) 입금액
5 FROM dual CONNECT BY LEVEL <= 10
6 ;
테이블이 생성되었습니다.
SQL> CREATE TABLE 출금 AS
2 SELECT ROWNUM 일련번호
3 , ROUND(DBMS_RANDOM.VALUE(1, 20)) 고객ID
4 , ROUND(DBMS_RANDOM.VALUE(1000, 1000000), -2) 출금액
5 FROM dual CONNECT BY LEVEL <= 10;
테이블이 생성되었습니다.
SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, '입금');
PL/SQL 처리가 정상적으로 완료되었습니다.
SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, '출금');
PL/SQL 처리가 정상적으로 완료되었습니다.
{CODE}
{CODE:SQL}
SQL> SELECT A.고객ID, A.입금액, B.출금액
2 FROM ( SELECT 고객ID, SUM( 입금액 ) 입금액 FROM 입금 GROUP BY 고객ID ) A
3 , ( SELECT 고객ID, SUM( 출금액 ) 출금액 FROM 출금 GROUP BY 고객ID ) B
4 WHERE B.고객ID(+) = A.고객ID
5 UNION ALL
6 SELECT 고객ID, NULL, 출금액
7 FROM (SELECT 고객ID, SUM( 출금액 ) 출금액 FROM 출금 GROUP BY 고객ID) A
8 WHERE NOT EXISTS (SELECT 'X' FROM 입금 WHERE 고객ID = A.고객ID);
고객ID 입금액 출금액
고객ID 입금액 출금액
12 개의 행이 선택되었습니다.
SQL> @XPLAN
Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
0 | SELECT STATEMENT | 1 | 12 | 00:00:00.01 | 12 | |||||
1 | UNION-ALL | 1 | 12 | 00:00:00.01 | 12 | |||||
| HASH JOIN OUTER | 1 | 9 | 9 | 00:00:00.01 | 6 | 1269K | 1269K | 1144K (0) | |
3 | VIEW | 1 | 9 | 9 | 00:00:00.01 | 3 | ||||
4 | HASH GROUP BY | 1 | 9 | 9 | 00:00:00.01 | 3 | 948K | 948K | 2206K (0) | |
5 | TABLE ACCESS FULL | 입금 | 1 | 10 | 10 | 00:00:00.01 | 3 | |||
6 | VIEW | 1 | 8 | 8 | 00:00:00.01 | 3 | ||||
7 | HASH GROUP BY | 1 | 8 | 8 | 00:00:00.01 | 3 | 948K | 948K | 1705K (0) | |
8 | TABLE ACCESS FULL | 출금 | 1 | 10 | 10 | 00:00:00.01 | 3 | |||
9 | HASH GROUP BY | 1 | 8 | 3 | 00:00:00.01 | 6 | 948K | 948K | 709K (0) | |
| HASH JOIN ANTI | 1 | 10 | 3 | 00:00:00.01 | 6 | 1269K | 1269K | 912K (0) | |
11 | TABLE ACCESS FULL | 출금 | 1 | 10 | 10 | 00:00:00.01 | 3 | |||
12 | TABLE ACCESS FULL | 입금 | 1 | 10 | 10 | 00:00:00.01 | 3 |
Predicate Information (identified by operation id):
2 - access("B"."고객ID"="A"."고객ID")
10 - access("고객ID"="고객ID")
{CODE}
NVL(A.고객ID,B.고객ID) 입금액 출금액
12 개의 행이 선택되었습니다.
SQL> @XPLAN
Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
0 | SELECT STATEMENT | 1 | 12 | 00:00:00.01 | 6 | |||||
1 | VIEW | VW_FOJ_0 | 1 | 9 | 12 | 00:00:00.01 | 6 | |||
| HASH JOIN FULL OUTER | 1 | 9 | 12 | 00:00:00.01 | 6 | 1269K | 1269K | 885K (0) | |
3 | VIEW | 1 | 8 | 8 | 00:00:00.01 | 3 | ||||
4 | HASH GROUP BY | 1 | 8 | 8 | 00:00:00.01 | 3 | 948K | 948K | 1706K (0) | |
5 | TABLE ACCESS FULL | 출금 | 1 | 10 | 10 | 00:00:00.01 | 3 | |||
6 | VIEW | 1 | 9 | 9 | 00:00:00.01 | 3 | ||||
7 | HASH GROUP BY | 1 | 9 | 9 | 00:00:00.01 | 3 | 948K | 948K | 2210K (0) | |
8 | TABLE ACCESS FULL | 입금 | 1 | 10 | 10 | 00:00:00.01 | 3 |
Predicate Information (identified by operation id):
2 - access("A"."고객ID"="B"."고객ID")
{CODE}
{CODE:SQL}
SQL> SELECT 고객ID, SUM( 입금액 ) 입금액, SUM( 출금액 ) 출금액
2 FROM (
3 SELECT 고객ID, 입금액, TO_NUMBER(NULL) 출금액 FROM 입금
4 UNION ALL
5 SELECT 고객ID, TO_NUMBER(NULL) , 출금액 FROM 출금
6 )
7 GROUP BY 고객ID;
고객ID 입금액 출금액
12 개의 행이 선택되었습니다.
SQL> @XPLAN
Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
0 | SELECT STATEMENT | 1 | 12 | 00:00:00.01 | 6 | |||||
1 | HASH GROUP BY | 1 | 9 | 12 | 00:00:00.01 | 6 | 843K | 843K | 1213K (0) | |
2 | VIEW | 1 | 20 | 20 | 00:00:00.01 | 6 | ||||
3 | UNION-ALL | 1 | 20 | 00:00:00.01 | 6 | |||||
4 | TABLE ACCESS FULL | 입금 | 1 | 10 | 10 | 00:00:00.01 | 3 | |||
5 | TABLE ACCESS FULL | 출금 | 1 | 10 | 10 | 00:00:00.01 | 3 |
19 개의 행이 선택되었습니다.
{CODE}