\- 실행계획은 SQL에 사용한 연산방식에 따라서 다양하게 나타난다.
{code:SQL} /* IN절을 사용한 SQL */ SELECT * FROM emp WHERE deptno IN ('10', '20'); |
/* OR을 사용한 SQL */
SELECT * FROM emp
WHERE deptno ='10' OR deptno = '20';
|| {code:SQL}
-----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 9 | 333 | 2 (0)| 00:00:01 |
| 1 | INLIST ITERATOR | | | | | |
| 2 | TABLE ACCESS BY INDEX ROWID| EMP | 9 | 333 | 2 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | EMP_DEPTNO_IDX | 9 | | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------
|
'IN'을 사용했는데도 INLIST ITERATOR가 나타나지 않는 경우{}
{code:SQL} SELECT * FROM emp WHERE job = 'SALES' OR sal = 3000; {code} | {code:SQL} -- | Id | Operation | Name | Rows | Bytes | Cost (%CPU) | Time |
0 | SELECT STATEMENT | 4 | 148 | 3 (0) | 00:00:01 | |
| TABLE ACCESS FULL | EMP | 4 | 148 | 3 (0) | 00:00:01 |
|
| {color:red}{*}USE_CONCAT 힌트를 사용하여 유도{*}{color}
{code:SQL}
SELECT /*+ USE_CONCAT */ *
FROM emp
WHERE job = 'SALES'
OR sal = 3000;
|
--------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4 | 148 | 4 (0)| 00:00:01 |
| 1 | CONCATENATION | | | | | |
| 2 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 37 | 2 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | EMP_SAL_IDX | 1 | | 1 (0)| 00:00:01 |
|* 4 | TABLE ACCESS BY INDEX ROWID| EMP | 3 | 111 | 2 (0)| 00:00:01 |
|* 5 | INDEX RANGE SCAN | EMP_IDX | 3 | | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------
|
{+}적용하지 않는 것이 바람직한 경우{+}
\- 조인의 연결고리가 'OR"조건을 가질 때 조인의 상대방이 넓은 처리범위를 가질 때
\- 동일 컬럼의 'OR'조건 : INLIST ITERATOR가 유리
\- 보다 효율적으로 처리범위를 줄일 수 있는 다른 액세스 경로가 있을때
\- 'OR'조건들 중에서 너무 넓은 처리범위를 가진 것들이 존재할 때
{+}SORT(UNIQUE)+
\- DISTINCT함수를 사용했을 때
\- 서브쿼리에서 제공자 역할을 할 때
{+}SORT(AGGREGATE)+
\- GROUP BY를 하지 않은 상태로, 전체 대상에 대해 그룹함수로 계산할 때
{code:SQL} SELECT SUM(sal) FROM emp WHERE deptno = 10; {code} | {code:SQL} --- | Id | Operation | Name | Rows | Bytes | Cost (%CPU) | Time |
0 | SELECT STATEMENT | 1 | 7 | 2 (0) | 00:00:01 | |
1 | SORT AGGREGATE | 1 | 7 | |||
2 | TABLE ACCESS BY INDEX ROWID | EMP | 5 | 35 | 2 (0) | 00:00:01 |
| INDEX RANGE SCAN | EMP_DEPTNO_IDX | 5 | 1 (0) | 00:00:01 |
|
*{+}SORT(GROUP BY)+*
\- GROUP BY를 사용하여 여러개의 다른 그룹으로 집결을 수행할 때 발생
\- 그룹의 개수가 많을수록 부담이 커짐. 이를 해결하기 위해 HASH(GROUP BY)
*{+}SORT(GROUP BY NOSORT)+*
\- GROUP BY에 나열된 컬럼이 처리주관 인덱스의 선행컬럼과 동일하여 추가적인 정렬작업이 필요없는 경우 나타남.
| {code:SQL}
SELECT deptno, SUM(sal)
FROM emp
WHERE deptno >10
GROUP BY deptno;
|
-----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 14 | 2 (0)| 00:00:01 |
| 1 | SORT GROUP BY NOSORT | | 2 | 14 | 2 (0)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID| EMP | 9 | 63 | 2 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | EMP_DEPTNO_IDX | 9 | | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------
|
{+}합집합(Union, Union All) 실행계획{+}
\- UNION은 최소 공배수 집합을 구해야 하므로, 추가로 SORT(UNIQUE)를 수행해야 한다.
{code:SQL} SELECT empno, ename FROM emp WHERE mgr = 7698 UNION SELECT empno, ename FROM emp WHERE deptno = 10; {code} | {code:SQL} | Id | Operation | Name | Rows | Bytes | Cost (%CPU) | Time |
0 | SELECT STATEMENT | 7 | 93 | 7 (58) | 00:00:01 | ||||
1 | SORT UNIQUE | 7 | 93 | 7 (58) | 00:00:01 | ||||
2 | UNION-ALL | ||||||||
| TABLE ACCESS FULL | EMP | 2 | 28 | 3 (0) | 00:00:01 | |||
4 | TABLE ACCESS BY INDEX ROWID | EMP | 5 | 65 | 2 (0) | 00:00:01 | |||
| INDEX RANGE SCAN | EMP_DEPTNO_IDX | 5 | 1 (0) | 00:00:01 | ||||
\- UNION ALL은 그런 처리가 필요하지 않다. | {code:SQL} SELECT empno, ename FROM emp WHERE deptno = 30 UNION SELECT empno, ename FROM emp WHERE deptno = 10; {code} | {code:SQL} --- | Id | Operation | Name | Rows | Bytes | Cost (%CPU) | Time |
0 | SELECT STATEMENT | 10 | 130 | 4 (50) | 00:00:01 | ||||
1 | UNION-ALL | ||||||||
2 | TABLE ACCESS BY INDEX ROWID | EMP | 5 | 65 | 2 (0) | 00:00:01 | |||
| INDEX RANGE SCAN | EMP_DEPTNO_IDX | 5 | 1 (0) | 00:00:01 | ||||
4 | TABLE ACCESS BY INDEX ROWID | EMP | 5 | 65 | 2 (0) | 00:00:01 | |||
| INDEX RANGE SCAN | EMP_DEPTNO_IDX | 5 | 1 (0) | 00:00:01 | ||||
{+}교집합(Intersection) 실행계획{+} \- 교집합은 양쪽집합 모두에 속하는 공통집합의 의미한다. \- 먼저 각각의 집합에서 유일한 집합을 구해야 한다. \- Sort Merge조인과 유사한 방법을 사용하여 양쪽집합을 유일하게 정렬한 다음 머지한다. | {code:SQL} SELECT empno, ename FROM emp WHERE mgr = 7698 INTERSECT SELECT empno, ename FROM emp WHERE deptno = 10; {code} | {code:SQL} | Id | Operation | Name | Rows | Bytes | Cost (%CPU) | Time |
0 | SELECT STATEMENT | 2 | 93 | 7 (58) | 00:00:01 | |
1 | INTERSECTION | |||||
2 | SORT UNIQUE | 2 | 28 | 4 (25) | 00:00:01 | |
| TABLE ACCESS FULL | EMP | 2 | 28 | 3 (0) | 00:00:01 |
4 | SORT UNIQUE | 5 | 65 | 3 (34) | 00:00:01 | |
5 | TABLE ACCESS BY INDEX ROWID | EMP | 5 | 65 | 2 (0) | 00:00:01 |
| INDEX RANGE SCAN | EMP_DEPTNO_IDX | 5 | 1 (0) | 00:00:01 |
|
*{+}차집합(Minus) 실행계획{+}*
\- 머지작업과 유사한 형태로 처리되며, 어느 한쪽을 기준으로 다른 쪽에 존재하면 제거하는 형식으로 처리된다.
\- SELECT절에 나열된 컬럼이 테이블의 기본키였다면 논리적으로 유일성이 보장되나, SORT(UNIQUE)은 발생된다.
\- WHERE절에 부여된 조건이 기본키를 =로 엑세스한 경우는 SORT(UNIQUE)이 발생되지 않는다.
| {code:SQL}
SELECT empno, ename
FROM emp WHERE mgr = 7698
MINUS
SELECT empno, ename
FROM emp WHERE deptno = 10;
|
------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 93 | 7 (58)| 00:00:01 |
| 1 | MINUS | | | | | |
| 2 | SORT UNIQUE | | 2 | 28 | 4 (25)| 00:00:01 |
|* 3 | TABLE ACCESS FULL | EMP | 2 | 28 | 3 (0)| 00:00:01 |
| 4 | SORT UNIQUE | | 5 | 65 | 3 (34)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID| EMP | 5 | 65 | 2 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | EMP_DEPTNO_IDX | 5 | | 1 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------
|
{code:SQL} SELECT * from emp WHERE sal>1000 AND ROWNUM < 5; {code} | {code:SQL} | Id | Operation | Name | Rows | Bytes | Cost (%CPU) | Time |
0 | SELECT STATEMENT | 4 | 148 | 2 (0) | 00:00:01 | |
| COUNT STOPKEY | |||||
2 | TABLE ACCESS BY INDEX ROWID | EMP | 6 | 222 | 2 (0) | 00:00:01 |
| INDEX RANGE SCAN | EMP_SAL_IDX | 13 | 1 (0) | 00:00:01 |
|