select ename, dname
from emp, dept
where emp.deptno = dept.deptno;
For x in (select * from emp)
Loop
Index lookup the ROWID for X.DEPTNO
select * from dept where ROWID = that ROWID
Output joined record
End loop
select /*+ first_rows */ ename, dname
from emp, dept
where emp.deptno(+) = dept.deptno;
select /*+ gather_plan_statistics */
t1.c1, t1.c2
from
t1
where
t1.c1 not in (select t2.c1 from t2)
;
@stat
-----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | Cost (%CPU)| A-Rows | A-Time | Buffers | Reads |
-----------------------------------------------------------------------------------------------------------
|* 1 | FILTER | | 1 | | | 9000 |00:00:01.03 | 69483 | 36 |
| 2 | TABLE ACCESS FULL| T1 | 1 | 10000 | 11 (0)| 10000 |00:00:00.06 | 638 | 30 |
|* 3 | TABLE ACCESS FULL| T2 | 10000 | 1 | 3 (0)| 1000 |00:00:00.96 | 68845 | 6 |
-----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter( IS NULL)
3 - filter(LNNVL("T2"."C1"<>:B1))
Subquery Unesting이 이루어 지지 않는다. Filter Operation이 사용 됨.
select /*+ gather_plan_statistics */
t1.c1, t1.c2
from
t1
where
t1.c1 not in (select t2.c1 from t2 where t2.c1 is not null) and
t1.c1 is not null
;
@stat
---------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | Cost (%CPU)| A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
---------------------------------------------------------------------------------------------------------------------------------
|* 1 | HASH JOIN RIGHT ANTI | | 1 | 9001 | 14 (8)| 9000 |00:00:00.07 | 645 | 1517K| 1517K| 1473K (0)|
|* 2 | INDEX FAST FULL SCAN| T2_N1 | 1 | 1000 | 2 (0)| 1000 |00:00:00.01 | 7 | | | |
|* 3 | TABLE ACCESS FULL | T1 | 1 | 10000 | 11 (0)| 10000 |00:00:00.05 | 638 | | | |
---------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("T1"."C1"="T2"."C1")
2 - filter("T2"."C1" IS NOT NULL)
3 - filter("T1"."C1" IS NOT NULL)
IS NOT NULL 조건이 부여된 경우 Hash Anti Join이 선택되었으며 일량이 645 Block으로 개선되었다.
Table Full Scan 대신 Index Fast Full Scan이 선택되었다.(B*Tree Index가 NULL값을 저장하지 않는다는 기본적인 전제 조건 때문이다.)
-- 11.1.0.6 에서 실행
select /*+ gather_plan_statistics */
t1.c1, t1.c2
from
t1
where
t1.c1 not in (select t2.c1 from t2)
;
@stat
----------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | Cost (%CPU)| A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
----------------------------------------------------------------------------------------------------------------------------------
|* 1 | HASH JOIN RIGHT ANTI NA| | 1 | 9000 | 15 (7)| 9000 |00:00:00.04 | 645 | 1517K| 1517K| 1514K (0)|
| 2 | TABLE ACCESS FULL | T2 | 1 | 1000 | 3 (0)| 1000 |00:00:00.01 | 7 | | | |
| 3 | TABLE ACCESS FULL | T1 | 1 | 10000 | 11 (0)| 10000 |00:00:00.03 | 638 | | | |
----------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("T1"."C1"="T2"."C1")
- 강좌 URL : http://www.gurubee.net/lecture/3563
- 구루비 강좌는 개인의 학습용으로만 사용 할 수 있으며, 다른 웹 페이지에 게재할 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^^
- 구루비 강좌는 서비스 제공을 위한 목적이나, 학원 홍보, 수익을 얻기 위한 용도로 사용 할 수 없습니다.