비교대상 | MINUS | NOT EXISTS |
---|---|---|
수행 SQL | SELECT .... FROM A MINUS SELECT ... FROM B | SELECT ... FROM A WHERE NOT EXISTS( SELECT ... FROM B WHERE B.XX = A.XX) |
수행방식 | 1. 테이블 A에서 데이터 추출 2. 추출된 데이터 SORT 연산 3. 테이블 B에서 데이터 추출 4. 추출된 데이터 SORT 연산 5. 2번과 4번 데이터 비교 후 최종 데이터 추출 | 1. 테이블 A에서 데이터 추출 2. 1번에서 추출한 데이터와 서브쿼리 테이블 B데이터와 존재 유무 체크 후 최종 데이터 추출 |
수행 순서 | 고정(A->B) | 변경가능(A->B OR B->A) |
테이블 수행 방식 | 테이블 A와 상관없이 별도로 데이터 추출 후 SORT 연산 수행 | 테이블 A의 추출 데이터를 이용한 인덱스 스캔 가능(조인 연결 키) 및 별도 수행도 가능 |
SQL 성능 | 불리 : 1. 테이블 A, B에서 추출한 데이터를 SORT 연산 시 성능 저하 2. 테이블 A에서 추출한 데이터가 적고, 데이터 B에 아무런 조건이 없는 경우 FULL TABLE SCAN으로 처리하여야 하고, 추출된 데이터를 SORT 연산을 수행해야 함 | 유리 : 적절한 인덱스 스캔을 수행하거나 FULL TABLE SCAN을 수행하는 등 SQL 성능에 가장 효율적인 방법을 선택하여 적용이 가능함 |
var b1 varchar2(10)
var b2 number
var b3 number
exec :b1 := 'A'
exec :b2 := 200000
exec :b3 := 300000
SELECT C1, C2, C3
FROM SUBQUERY_T2
WHERE C2 = :B1
AND C1 >= :B2
AND C1 <= :B3
MINUS
SELECT C4, C5, C6
FROM SUBQUERY_T1
Call Count CPU Time Elapsed Time Disk Query Current Rows
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Parse 1 0.000 0.001 0 0 0 0
Execute 1 0.000 0.001 0 0 0 0
Fetch 21 11.357 11.608 37509 44145 0 1923
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Total 23 11.357 11.611 37509 44145 0 1923
Misses in library cashe during parse : 1
Optimizer Goal : ALL_ROWS
Parsing user : SCOTT (ID=84)
Rows Row Source Operation
------- -----------------------------------------------------------------------
1923 MINUS (cr=44145 pr=37509 pw=0 time=512 us)
3846 SORT UNIQUE (cr=275 pr=0 pw=0 time=384 us cost=276 size=46152 card=3846)
3846 FILTER (cr=275 pr=0 pw=0 time=6945 us)
3846 TABLE ACCESS BY INDEX ROWID SUBQUERY_T2 (cr=275 pr=0 pw=0 time=5705 us cost=275 size=46152 card=3846)
3846 INDEX RANGE SCAN SUBQUERY_T2_IDX_01 (cr=12 pr=0 pw=0 time=1240 us cost=12 size=0 card=3846)
250000 SORT UNIQUE (cr=43870 pr=37509 pw=0 time=38894 us cost=83720 size=192000000 card=16000000)
16000000 TABLE ACCESS FULL SUBQUERY_T1 (cr=43870 pr=37509 pw=0 time=5179007 us cost=10329 size=192000000 card=16000000)
SELECT C1, C2, C3
FROM SUBQUERY_T2 T2
WHERE C2 = :B1
AND C1 >= :B2
AND C1 <= :B3
AND NOT EXISTS (SELECT /*+ UNNEST NL_AJ */
'X'
FROM SUBQUERY_T1 T1
WHERE T1.C4 = T2.C1
AND T1.C5 = T2.C2
AND T1.C6 = T2.C3)
Call Count CPU Time Elapsed Time Disk Query Current Rows
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Parse 1 0.000 0.001 0 0 0 0
Execute 1 0.000 0.004 0 0 0 0
Fetch 21 0.047 0.111 122 4311 0 1923
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Total 23 0.047 0.115 122 4311 0 1923
Misses in library cashe during parse : 1
Misses in library cashe during execute : 1
Optimizer Goal : ALL_ROWS
Parsing user : SCOTT (ID=84)
Rows Row Source Operation
------- -----------------------------------------------------------------------
1923 FILTER (cr=4311 pr=122 pw=0 time=13454 us)
1923 NESTED LOOPS ANTI (cr=4311 pr=122 pw=0 time=12428 us cost=32983 size=912 card=38)
3846 TABLE ACCESS BY INDEX ROWID SUBQUERY_T2 (cr=314 pr=0 pw=0 time=9922 us cost=275 size=46152 card=3846)
3846 INDEX RANGE SCAN SUBQUERY_T2_IDX_01 (cr=32 pr=0 pw=0 time=2976 us cost=12 size=0 card=3846)
1923 TABLE ACCESS BY INDEX ROWID SUBQUERY_T1 (cr=3997 pr=122 pw=0 time=0 us cost=15 size=1476960 card=123080)
1923 INDEX RANGE SCAN SUBQUERY_T1_IDX1_01 (cr=3879 pr=0 pw=0 time=0 us cost=2 size=0 card=13)
NOT EXISTS 주의 할 점
var b1 varchar2(10)
var b2 number
var b3 number
exec :b1 := 'A'
exec :b2 := 200000
exec :b3 := 300000
SELECT /*+ LEADING(T2 T1 T3) USE_NL(T2 T1 T3) */
DISTINCT T2.C1, T2.C2, T3.C3
FROM SUBQUERY_T2 T2,
SUBQUERY_T1 T1,
SUBQUERY_T3 T3
WHERE T2.C2 = :B1
AND T2.C1 >= :B2
AND T2.C1 <= :B3
AND T2.C1 = T1.C4
AND T2.C2 = T1.C5
AND T1.C4 = T3.C1
AND T1.C5 = T3.C2
Call Count CPU Time Elapsed Time Disk Query Current Rows
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Parse 1 0.000 0.001 0 0 0 0
Execute 1 0.000 0.052 0 0 0 0
Fetch 21 0.374 0.391 133 6698 0 1923
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Total 23 0.374 0.444 133 6698 0 1923
Misses in library cashe during parse : 1
Misses in library cashe during execute : 1
Optimizer Goal : ALL_ROWS
Parsing user : SCOTT (ID=84)
Rows Row Source Operation
------- -----------------------------------------------------------------------
1923 HASH UNIQUE (cr=6698 pr=133 pw=0 time=768 us cost=14199 size=4992 card=192)
123072 FILTER (cr=6698 pr=133 pw=0 time=1607471 us)
123072 NESTED LOOPS (cr=6698 pr=133 pw=0 time=1590711 us)
123072 NESTED LOOPS (cr=6580 pr=133 pw=0 time=1440007 us cost=14198 size=4992 card=192)
123072 NESTED LOOPS (cr=4186 pr=0 pw=0 time=598979 us cost=4482 size=67984 card=4856)
3846 INDEX RANGE SCAN SUBQUERY_T2_IDX_01 (cr=12 pr=0 pw=0 time=992 us cost=12 size=26922 card=3846)
123072 INDEX RANGE SCAN SUBQUERY_T1_IDX1_01 (cr=4174 pr=0 pw=0 time=42777 us cost=2 size=7 card=1)
123072 INDEX RANGE SCAN SUBQUERY_T3_IDX_01 (cr=2394 pr=133 pw=0 time=0 us cost=1 size=0 card=1)
123072 TABLE ACCESS BY INDEX ROWID SUBQUERY_T3 (cr=118 pr=0 pw=0 time=0 us cost=2 size=12 card=1)
SUM/COUNT같은 그룹함수를 수행하는 경우는 데이터가 훼손될 수 있으므로 데이터 정합성 체크를 필히 수행햐 함.
ELECT /*+ LEADING (T2 T1@SUB T3) USE_NL(T1 T2@SUB T3) */
DISTINCT T2.C1, T2.C2, T3.C3
FROM SUBQUERY_T2 T2,
SUBQUERY_T3 T3
WHERE T2.C2 = :B1
AND T2.C1 >= :B2
AND T2.C1 <= :B3
AND EXISTS (SELECT /*+ QB_NAME(SUB) */ 'X'
FROM SUBQUERY_T1 T1
WHERE T2.C1 = T1.C4
AND T2.C2 = T1.C5
AND T1.C4 = T3.C1
AND T1.C5 = T3.C2)
Call Count CPU Time Elapsed Time Disk Query Current Rows
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Parse 1 0.000 0.000 0 0 0 0
Execute 1 0.000 0.000 0 0 0 0
Fetch 21 0.078 0.079 0 5692 0 1923
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Total 23 0.078 0.079 0 5692 0 1923
Misses in library cashe during parse : 0
Optimizer Goal : ALL_ROWS
Parsing user : SCOTT (ID=84)
Rows Row Source Operation
------- -----------------------------------------------------------------------
1923 HASH UNIQUE (cr=5692 pr=0 pw=0 time=1153 us cost=14199 size=2106 card=81)
1923 FILTER (cr=5692 pr=0 pw=0 time=75078 us)
1923 NESTED LOOPS (cr=5692 pr=0 pw=0 time=74717 us)
1923 NESTED LOOPS (cr=5574 pr=0 pw=0 time=71954 us cost=14198 size=2106 card=81)
1923 NESTED LOOPS (cr=4182 pr=0 pw=0 time=66068 us cost=4482 size=67984 card=4856)
3846 INDEX RANGE SCAN SUBQUERY_T2_IDX_01 (cr=12 pr=0 pw=0 time=248 us cost=12 size=26922 card=3846)
1923 SORT UNIQUE (cr=4170 pr=0 pw=0 time=0 us cost=2 size=7 card=1)
123072 INDEX RANGE SCAN SUBQUERY_T1_IDX1_01 (cr=4170 pr=0 pw=0 time=42084 us cost=2 size=7 card=1)
1923 INDEX RANGE SCAN SUBQUERY_T3_IDX_01 (cr=1392 pr=0 pw=0 time=0 us cost=1 size=0 card=1)
1923 TABLE ACCESS BY INDEX ROWID SUBQUERY_T3 (cr=118 pr=0 pw=0 time=0 us cost=2 size=12 card=1)
ALTER SYSTEM SET "_optim_peek_user_binds" = FALSE;
var b1 varchar2(10)
var b2 number
var b3 number
var b4 varchar2(10)
var b5 number
var b6 number
var b7 varchar2(10)
var b8 number
var b9 number
exec :b1 := 'A'
exec :b2 := 200000
exec :b3 := 100000
exec :b4 := '%'
exec :b5 := 100000
exec :b6 := 300000
exec :b7 := '%'
exec :b8 := 100000
exec :b9 := 300000
SELECT T1.*
FROM SUBQUERY_T1 T1
WHERE EXISTS (SELECT 'X'
FROM SUBQUERY_T2 T2
WHERE T2.C2 LIKE :B1
AND T2.C3 >= :B2
AND T2.C3 <= :B3
AND T2.C1 = T1.C4
AND T2.C2 = T1.C5)
AND EXISTS (SELECT 'X'
FROM SUBQUERY_T3 T3
WHERE T3.C2 LIKE :B4
AND T3.C3 >= :B5
AND T3.C3 <= :B6
AND T3.C1 = T1.C4)
AND EXISTS (SELECT 'X'
FROM SUBQUERY_T1 T11
WHERE T11.C5 LIKE :B7
AND T11.C4 >= :B8
AND T11.C4 <= :B9
AND T11.C4 = T1.C4)
Call Count CPU Time Elapsed Time Disk Query Current Rows
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Parse 1 0.000 0.002 0 0 0 0
Execute 1 0.016 0.009 0 0 0 0
Fetch 4 8.471 188.113 19035 437582 0 256
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Total 6 8.486 188.124 19035 437582 0 256
Misses in library cashe during parse : 1
Optimizer Goal : ALL_ROWS
Parsing user : SCOTT (ID=84)
Rows Row Source Operation
------- -----------------------------------------------------------------------
256 FILTER (cr=437582 pr=19035 pw=0 time=183345 us)
256 NESTED LOOPS SEMI (cr=437582 pr=19035 pw=0 time=182835 us cost=17 size=43 card=1)
246144 NESTED LOOPS SEMI (cr=434790 pr=19035 pw=0 time=286116480 us cost=15 size=31 card=1)
246144 NESTED LOOPS (cr=427094 pr=19035 pw=0 time=279875072 us cost=13 size=24 card=1)
100002 SORT UNIQUE (cr=974 pr=371 pw=0 time=155883 us cost=9 size=12 card=1)
100002 TABLE ACCESS BY INDEX ROWID SUBQUERY_T3 (cr=974 pr=371 pw=0 time=166881 us cost=9 size=12 card=1)
200001 INDEX RANGE SCAN SUBQUERY_T3_IDX_01 (cr=504 pr=371 pw=0 time=128342 us cost=8 size=0 card=87)
246144 TABLE ACCESS BY INDEX ROWID SUBQUERY_T1 (cr=426120 pr=18664 pw=0 time=142582224 us cost=3 size=12 card=1)
246144 INDEX RANGE SCAN SUBQUERY_T1_IDX1_01 (cr=176999 pr=0 pw=0 time=722862 us cost=2 size=0 card=1)
3846 INDEX RANGE SCAN SUBQUERY_T1_IDX1_01 (cr=7696 pr=0 pw=0 time=0 us cost=2 size=14000 card=2000)
4 TABLE ACCESS BY INDEX ROWID SUBQUERY_T2 (cr=2792 pr=0 pw=0 time=0 us cost=2 size=12 card=1)
3846 INDEX UNIQUE SCAN PK_SUBQUERY_2 (cr=2526 pr=0 pw=0 time=0 us cost=1 size=0 card=1)
SELECT /*+ LEADING(T2 T1) USE_NL(T2 T1) */
T1.*
FROM SUBQUERY_T1 T1,
(SELECT DISTINCT T2.C1,
T2.C2
FROM SUBQUERY_T2 T2
WHERE T2.C2 LIKE :B1
AND T2.C3 >= :B2
AND T2.C3 <= :B3) T2
WHERE T2.C1 = T1.C4
AND T2.C2 = T1.C5
AND EXISTS (SELECT 'X'
FROM SUBQUERY_T3 T3
WHERE T3.C2 LIKE :B4
AND T3.C3 >= :B5
AND T3.C3 <= :B6
AND T3.C1 = T1.C4)
AND EXISTS (SELECT 'X'
FROM SUBQUERY_T1 T11
WHERE T11.C5 LIKE :B7
AND T11.C4 >= :B8
AND T11.C4 <= :B9
AND T11.C4 = T1.C4)
Call Count CPU Time Elapsed Time Disk Query Current Rows
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Parse 1 0.000 0.000 0 0 0 0
Execute 1 0.000 0.000 0 0 0 0
Fetch 4 0.062 0.074 0 1248 0 256
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Total 6 0.062 0.075 0 1248 0 256
Misses in library cashe during parse : 0
Optimizer Goal : ALL_ROWS
Parsing user : SCOTT (ID=84)
Rows Row Source Operation
------- -----------------------------------------------------------------------
256 FILTER (cr=1248 pr=0 pw=0 time=56100 us)
256 NESTED LOOPS SEMI (cr=1248 pr=0 pw=0 time=55845 us cost=21 size=43 card=1)
256 NESTED LOOPS SEMI (cr=1234 pr=0 pw=0 time=32895 us cost=18 size=31 card=1)
256 NESTED LOOPS (cr=1223 pr=0 pw=0 time=28560 us cost=16 size=24 card=1)
4 TABLE ACCESS BY INDEX ROWID SUBQUERY_T2 (cr=952 pr=0 pw=0 time=276 us cost=13 size=12 card=1)
200001 INDEX RANGE SCAN PK_SUBQUERY_2 (cr=423 pr=0 pw=0 time=32117 us cost=7 size=0 card=2250)
256 TABLE ACCESS BY INDEX ROWID SUBQUERY_T1 (cr=271 pr=0 pw=0 time=7623 us cost=3 size=12 card=1)
256 INDEX RANGE SCAN SUBQUERY_T1_IDX1_01 (cr=15 pr=0 pw=0 time=4977 us cost=2 size=0 card=1)
4 INDEX RANGE SCAN SUBQUERY_T1_IDX1_01 (cr=11 pr=0 pw=0 time=0 us cost=2 size=14000 card=2000)
4 TABLE ACCESS BY INDEX ROWID SUBQUERY_T3 (cr=14 pr=0 pw=0 time=0 us cost=3 size=12 card=1)
4 INDEX RANGE SCAN SUBQUERY_T3_IDX_01 (cr=11 pr=0 pw=0 time=0 us cost=2 size=0 card=1)
- 실제로는 PK_SUBQUERY_2 를 탔음
SELECT /*+ LEADING(T2 T1) USE_NL(T2 T1) INDEX(T2 SUBQUERY_T2_IDX_01) */
T1.*
FROM SUBQUERY_T1 T1,
(SELECT DISTINCT T2.C1,
T2.C2
FROM SUBQUERY_T2 T2
WHERE T2.C2 LIKE :B1
AND T2.C3 >= :B2
AND T2.C3 <= :B3) T2
WHERE T2.C1 = T1.C4
AND T2.C2 = T1.C5
AND EXISTS (SELECT 'X'
FROM SUBQUERY_T3 T3
WHERE T3.C2 LIKE :B4
AND T3.C3 >= :B5
AND T3.C3 <= :B6
AND T3.C1 = T1.C4)
AND EXISTS (SELECT 'X'
FROM SUBQUERY_T1 T11
WHERE T11.C5 LIKE :B7
AND T11.C4 >= :B8
AND T11.C4 <= :B9
AND T11.C4 = T1.C4)
Call Count CPU Time Elapsed Time Disk Query Current Rows
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Parse 1 0.000 0.000 0 0 0 0
Execute 1 0.000 0.000 0 0 0 0
Fetch 4 0.016 0.017 0 869 0 256
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Total 6 0.016 0.018 0 869 0 256
Misses in library cashe during parse : 0
Optimizer Goal : ALL_ROWS
Parsing user : SCOTT (ID=84)
Rows Row Source Operation
------- -----------------------------------------------------------------------
256 FILTER (cr=869 pr=0 pw=0 time=22695 us)
256 NESTED LOOPS SEMI (cr=869 pr=0 pw=0 time=22695 us cost=65 size=43 card=1)
256 NESTED LOOPS SEMI (cr=855 pr=0 pw=0 time=17212 us cost=62 size=31 card=1)
256 NESTED LOOPS (cr=844 pr=0 pw=0 time=14535 us cost=60 size=24 card=1)
4 TABLE ACCESS BY INDEX ROWID SUBQUERY_T2 (cr=573 pr=0 pw=0 time=36 us cost=57 size=12 card=1)
7692 INDEX RANGE SCAN SUBQUERY_T2_IDX_01 (cr=45 pr=0 pw=0 time=8699 us cost=51 size=0 card=87)
256 TABLE ACCESS BY INDEX ROWID SUBQUERY_T1 (cr=271 pr=0 pw=0 time=5166 us cost=3 size=12 card=1)
256 INDEX RANGE SCAN SUBQUERY_T1_IDX1_01 (cr=15 pr=0 pw=0 time=3780 us cost=2 size=0 card=1)
4 INDEX RANGE SCAN SUBQUERY_T1_IDX1_01 (cr=11 pr=0 pw=0 time=0 us cost=2 size=14000 card=2000)
4 TABLE ACCESS BY INDEX ROWID SUBQUERY_T3 (cr=14 pr=0 pw=0 time=0 us cost=3 size=12 card=1)
4 INDEX RANGE SCAN SUBQUERY_T3_IDX_01 (cr=11 pr=0 pw=0 time=0 us cost=2 size=0 card=1)
- 강좌 URL : http://www.gurubee.net/lecture/3782
- 구루비 강좌는 개인의 학습용으로만 사용 할 수 있으며, 다른 웹 페이지에 게재할 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^^
- 구루비 강좌는 서비스 제공을 위한 목적이나, 학원 홍보, 수익을 얻기 위한 용도로 사용 할 수 없습니다.