[사례연구] Nested와 Correlated Sub-query의 동시 사용
本 사례에서는 요구사항의 특성으로 인해 SQL 의 WHERE 절에 IN과
EXISTS를 동시에 사용할 수 밖에 없는 경우, 이를 효과적으로 처리
할 수 있는 방안을 찾고자 한다.
- 요구사항
전체 과정(COURSE_CODE)에 대하여 2000년에 신청자가 전혀 없거나
500 명 미만인 과정에 대해 과정코드와 과정명을 조회하고자 합니다.
本 사례에서는 요구사항의 특성으로 인해 SQL 의 WHERE 절에 IN과
EXISTS를 동시에 사용할 수 밖에 없는 경우, 이를 효과적으로 처리
할 수 있는 방안을 찾고자 한다.
- 요구사항
전체 과정(COURSE_CODE)에 대하여 2000년에 신청자가 전혀 없거나
500 명 미만인 과정에 대해 과정코드와 과정명을 조회하고자 합니다.
전제조건
<옵티마이저>
Rule Based Optimzer
<인덱스 정보>
EC_COURSE : EC_COURSE_PK : COURSE_CODE
EC_APPLY : EC_APPLY_PK : COURSE_CODE + YEAR + COURSE_SQ_NO +
MEMBER_TYPE + MEMBER_ID
Rule Based Optimzer
<인덱스 정보>
EC_COURSE : EC_COURSE_PK : COURSE_CODE
EC_APPLY : EC_APPLY_PK : COURSE_CODE + YEAR + COURSE_SQ_NO +
MEMBER_TYPE + MEMBER_ID
Before Tuning
SELECT A.COURSE_CODE, A.COURSE_NAME
FROM EC_COURSE A
WHERE A.COURSE_CODE IN (SELECT COURSE_CODE
FROM EC_APPLY
WHERE YEAR = '2000'
GROUP BY COURSE_CODE
HAVING COUNT(COURSE_CODE) < 500)
OR NOT EXISTS (SELECT 'X'
FROM EC_APPLY C
WHERE C.COURSE_CODE = A.COURSE_CODE
AND C.YEAR = '2000');
FROM EC_COURSE A
WHERE A.COURSE_CODE IN (SELECT COURSE_CODE
FROM EC_APPLY
WHERE YEAR = '2000'
GROUP BY COURSE_CODE
HAVING COUNT(COURSE_CODE) < 500)
OR NOT EXISTS (SELECT 'X'
FROM EC_APPLY C
WHERE C.COURSE_CODE = A.COURSE_CODE
AND C.YEAR = '2000');
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.01 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 113 727.99 728.91 20171550 22759487 6784 1674
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 115 728.00 728.91 20171550 22759487 6784 1674
Rows Execution Plan
------- ---------------------------------------------------
0 SELECT STATEMENT GOAL: CHOOSE
1674 FILTER <------------------ 서브 쿼리를 나중에 실행!
1696 TABLE ACCESS (FULL) OF 'EC_COURSE'
1695 FILTER <------------------ 'HAVING절'에 대한 작업
646141 SORT (GROUP BY)
101033865 TABLE ACCESS (FULL) OF 'EC_APPLY'
1308 INDEX (RANGE SCAN) OF 'EC_APPLY_PK' (UNIQUE)
------- ---------------------------------------------------
0 SELECT STATEMENT GOAL: CHOOSE
1674 FILTER <------------------ 서브 쿼리를 나중에 실행!
1696 TABLE ACCESS (FULL) OF 'EC_COURSE'
1695 FILTER <------------------ 'HAVING절'에 대한 작업
646141 SORT (GROUP BY)
101033865 TABLE ACCESS (FULL) OF 'EC_APPLY'
1308 INDEX (RANGE SCAN) OF 'EC_APPLY_PK' (UNIQUE)
UNION ALL을 활용한 튜닝
SELECT A.COURSE_CODE, A.COURSE_NAME
FROM EC_COURSE A
WHERE A.COURSE_CODE IN (SELECT COURSE_CODE
FROM EC_APPLY
WHERE YEAR = '2000'
GROUP BY COURSE_CODE
HAVING COUNT(COURSE_CODE) < 500)
UNION ALL
SELECT A.COURSE_CODE, A.COURSE_NAME
FROM EC_COURSE A
WHERE NOT EXISTS (SELECT 'X'
FROM EC_APPLY C
WHERE C.COURSE_CODE = A.COURSE_CODE
AND C.YEAR = '2000')
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 113 0.52 0.52 13013 19560 0 1674
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 115 0.52 0.52 13013 19560 0 1674
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 113 0.52 0.52 13013 19560 0 1674
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 115 0.52 0.52 13013 19560 0 1674
Rows Execution Plan
------- ---------------------------------------------------
0 SELECT STATEMENT GOAL: CHOOSE
1674 UNION-ALL
387 NESTED LOOPS
407 VIEW OF 'VW_NSO_1'
407 FILTER
428 SORT (GROUP BY)
59607 TABLE ACCESS (FULL) OF 'EC_APPLY'
387 TABLE ACCESS (BY INDEX ROWID) OF 'EC_COURSE'
387 INDEX (UNIQUE SCAN) OF 'EC_COURSE_PK' (UNIQUE)
1287 FILTER
1695 TABLE ACCESS (FULL) OF 'EC_COURSE'
408 INDEX (RANGE SCAN) OF 'EC_APPLY_PK' (UNIQUE)
하나의 서브쿼리를 활용한 튜닝
SELECT A.COURSE_CODE, A.COURSE_NAME
FROM EC_COURSE A
WHERE 500 > (SELECT COUNT(*) FROM EC_APPLY B
WHERE B.COURSE_CODE = A.COURSE_CODE
AND B.YEAR = '2000')
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.01 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 113 0.05 0.06 15 3989 0 1674
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 115 0.06 0.06 15 3989 0 1674
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.01 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 113 0.05 0.06 15 3989 0 1674
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 115 0.06 0.06 15 3989 0 1674
Rows Execution Plan
------- ---------------------------------------------------
0 SELECT STATEMENT GOAL: CHOOSE
1674 FILTER
1695 TABLE ACCESS (FULL) OF 'EC_COURSE'
1695 SORT (AGGREGATE)
59518 INDEX (RANGE SCAN) OF 'EC_APPLY_PK' (UNIQUE)
조인을 활용한 튜닝
SELECT A.COURSE_CODE, A.COURSE_NAME
FROM EC_COURSE A, EC_APPLY B
WHERE A.COURSE_CODE = B.COURSE_CODE(+) --- EC_APPLY에는 데이터가 없을 수도 있기 때문에 없다고 배제하면 문제가 발생
AND B.YEAR(+) = '2000'
GROUP BY A.COURSE_CODE, A.COURSE_NAME
HAVING COUNT(B.COURSE_CODE) < 500
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 113 0.13 0.13 30 3771 0 1674
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 115 0.13 0.14 30 3771 0 1674
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 113 0.13 0.13 30 3771 0 1674
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 115 0.13 0.14 30 3771 0 1674
Rows Execution Plan
------- ---------------------------------------------------
0 SELECT STATEMENT GOAL: CHOOSE
1674 FILTER
1695 SORT (GROUP BY)
60805 NESTED LOOPS (OUTER)
1695 TABLE ACCESS (FULL) OF 'EC_COURSE'
59518 INDEX (RANGE SCAN) OF 'EC_APPLY_PK' (UNIQUE)
'04번. IT 힌트얻기 > ▶ DB Tuning' 카테고리의 다른 글
[Tuning] 분석함수의 활용 (셀프조인의 해결) (0) | 2011.10.12 |
---|---|
[Tuning] Scalar 서브쿼리 활용 (0) | 2011.10.12 |
[Tuning] SET AUTOTRACE TRACEONLY EXPLAIN (0) | 2011.10.12 |
[Tuning] 서브쿼리를 통한 튜닝 (0) | 2011.10.12 |
[Tuning]결합인덱스 문제 관련 (0) | 2011.10.11 |