select count(*)
from
(
select /*+ gather_plan_statistics */
t1.c1, t1.c2
from
t1
where
t1.c1 in (select t2.c1 from t2)
)
;
@stat
-------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | Cost (%CPU)| A-Rows | A-Time | Buffers | Reads | OMem | 1Mem | Used-Mem |
-------------------------------------------------------------------------------------------------------------------------------------------
| 1 | SORT AGGREGATE | | 1 | 1 | | 1 |00:00:00.03 | 31 | 1 | | | |
|* 2 | HASH JOIN RIGHT SEMI | | 1 | 999 | 10 (10)| 1000 |00:00:00.04 | 31 | 1 | 1517K| 1517K| 1493K (0)|
| 3 | INDEX FAST FULL SCAN| T2_N1 | 1 | 1000 | 2 (0)| 1000 |00:00:00.03 | 7 | 1 | | | |
| 4 | INDEX FAST FULL SCAN| T1_N1 | 1 | 10000 | 7 (0)| 10000 |00:00:00.04 | 24 | 0 | | | |
-------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("T1"."C1"="T2"."C1")
select count(*)
from
(
select /*+ gather_plan_statistics */
t1.c1, t1.c2
from
t1
where
t1.c1 in (select /*+ no_unnest */ t2.c1 from t2)
)
;
@stat
----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | Cost (%CPU)| A-Rows | A-Time | Buffers |
----------------------------------------------------------------------------------------------------
| 1 | SORT AGGREGATE | | 1 | 1 | | 1 |00:00:00.19 | 20038 |
|* 2 | FILTER | | 1 | | | 1000 |00:00:00.03 | 20038 |
| 3 | TABLE ACCESS FULL| T1 | 1 | 10000 | 11 (0)| 10000 |00:00:00.04 | 38 |
|* 4 | INDEX RANGE SCAN | T2_N1 | 10000 | 1 | 1 (0)| 1000 |00:00:00.13 | 20000 |
----------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter( IS NOT NULL)
4 - access("T2"."C1"=:B1)
select * from (
select /*+ gather_plan_statistics */
t1.c1, t1.c2
from
t1
where
t1.c1 in (select t2.c1 from t2)
)
where rownum <= 1;
@stat
----------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | Cost (%CPU)| A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
----------------------------------------------------------------------------------------------------------------------------------
|* 1 | COUNT STOPKEY | | 1 | | | 1 |00:00:00.01 | 12 | | | |
|* 2 | HASH JOIN RIGHT SEMI | | 1 | 999 | 5 (20)| 1 |00:00:00.01 | 12 | 1517K| 1517K| 1439K (0)|
| 3 | INDEX FAST FULL SCAN| T2_N1 | 1 | 1000 | 2 (0)| 1000 |00:00:00.01 | 7 | | | |
| 4 | TABLE ACCESS FULL | T1 | 1 | 10000 | 2 (0)| 316 |00:00:00.01 | 5 | | | |
----------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(ROWNUM<=1)
2 - access("T1"."C1"="T2"."C1")
==> 테스트에서는 Hash Join (책과 다름. 책 참조.)
select * from (
select /*+ gather_plan_statistics */
t1.c1, t1.c2
from
t1
where
t1.c1 in (select /*+ no_unnest */ t2.c1 from t2)
)
where rownum <= 1;
@stat
----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | Cost (%CPU)| A-Rows | A-Time | Buffers |
----------------------------------------------------------------------------------------------------
|* 1 | COUNT STOPKEY | | 1 | | | 1 |00:00:00.01 | 637 |
|* 2 | FILTER | | 1 | | | 1 |00:00:00.01 | 637 |
| 3 | TABLE ACCESS FULL| T1 | 1 | 10000 | 11 (0)| 316 |00:00:00.01 | 5 |
|* 4 | INDEX RANGE SCAN | T2_N1 | 316 | 1 | 1 (0)| 1 |00:00:00.01 | 632 |
----------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(ROWNUM<=1)
2 - filter( IS NOT NULL)
4 - access("T2"."C1"=:B1)
==> 책과 결과 틀림. 책 참조
select /*+ gather_plan_statistics */
t1.c1, t1.c2
from
t1
where
t1.c1 in (select t2.c1 from t2) and
t1.c1 = 1
;
@stat
-------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | Cost (%CPU)| A-Rows | A-Time | Buffers |
-------------------------------------------------------------------------------------------------------------
| 1 | NESTED LOOPS SEMI | | 1 | 1 | 3 (0)| 1 |00:00:00.01 | 6 |
| 2 | TABLE ACCESS BY INDEX ROWID| T1 | 1 | 1 | 2 (0)| 1 |00:00:00.01 | 4 |
|* 3 | INDEX RANGE SCAN | T1_N1 | 1 | 1 | 1 (0)| 1 |00:00:00.01 | 3 |
|* 4 | INDEX RANGE SCAN | T2_N1 | 1 | 1 | 1 (0)| 1 |00:00:00.01 | 2 |
-------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("T1"."C1"=1)
4 - access("T2"."C1"=1)
filter("T1"."C1"="T2"."C1")
Subquery가 사용된 Query에서 Subquery Unnesting이 성공적으로 이루어지는지 항상 확인해야 한다.
- 강좌 URL : http://www.gurubee.net/lecture/3872
- 구루비 강좌는 개인의 학습용으로만 사용 할 수 있으며, 다른 웹 페이지에 게재할 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^^
- 구루비 강좌는 서비스 제공을 위한 목적이나, 학원 홍보, 수익을 얻기 위한 용도로 사용 할 수 없습니다.