
nlj_batching(inner 테이블 별칭) hint 사용, prefetch로 단계를 내려가러면 no_nlj_batching(inner 테이블 별칭) hint 사용select /*+ gather_plan_statistics */ e.employee_id, e.salary, d.department_name
from hr.employees e, hr.departments d
where e.department_id = d.department_id
and d.location_id = 2500;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
Plan hash value: 2696597736
------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 34 |00:00:00.01 | 11 | 3 |
| 1 | NESTED LOOPS | | 1 | 10 | 34 |00:00:00.01 | 11 | 3 |
| 2 | NESTED LOOPS | | 1 | 10 | 34 |00:00:00.01 | 7 | 3 |
| 3 | TABLE ACCESS BY INDEX ROWID BATCHED| DEPARTMENTS | 1 | 1 | 1 |00:00:00.01 | 3 | 2 |
|* 4 | INDEX RANGE SCAN | DEPT_LOCATION_IX | 1 | 1 | 1 |00:00:00.01 | 2 | 1 |
|* 5 | INDEX RANGE SCAN | EMP_DEPARTMENT_IX | 1 | 10 | 34 |00:00:00.01 | 4 | 1 |
| 6 | TABLE ACCESS BY INDEX ROWID | EMPLOYEES | 34 | 10 | 34 |00:00:00.01 | 4 | 0 |
------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("D"."LOCATION_ID"=2500)
5 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
db file sequential read(multi block I/O가 아니라 single block I/O 라는 증거) 발생할 수 있는데 table prefetch기능이 수행되면 df file paralle reads 이벤트가 같이 발생한다.nlj_prefetch(inner 테이블 별칭) hint 사용, 적용하지 않을때 no_nlj_prefetch(inner 테이블 별칭) hint 사용select /*+ gather_plan_statistics no_nlj_batching(e) */ e.employee_id, e.salary, d.department_name
from hr.employees e, hr.departments d
where e.department_id = d.department_id
and d.location_id = 2500;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
Plan hash value: 17944037
------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 0 | | 0 |00:00:00.01 | 0 | 0 |
| 1 | TABLE ACCESS BY INDEX ROWID BATCHED | EMPLOYEES | 1 | 10 | 34 |00:00:00.01 | 11 | 4 |
| 2 | NESTED LOOPS | | 1 | 10 | 34 |00:00:00.01 | 7 | 3 |
| 3 | TABLE ACCESS BY INDEX ROWID BATCHED| DEPARTMENTS | 1 | 1 | 1 |00:00:00.01 | 3 | 2 |
|* 4 | INDEX RANGE SCAN | DEPT_LOCATION_IX | 1 | 1 | 1 |00:00:00.01 | 2 | 1 |
|* 5 | INDEX RANGE SCAN | EMP_DEPARTMENT_IX | 1 | 10 | 34 |00:00:00.01 | 4 | 1 |
------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("D"."LOCATION_ID"=2500)
5 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
select /*+ optimizer_features_enable('10.1.0') gather_plan_statistics leading(d,e) use_nl(e) no_nlj_prefetch(e) */ e.employee_id, e.salary, d.department_name
from hr.employees e, hr.departments d
where e.department_id = d.department_id
and d.location_id = 2500;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
Plan hash value: 968347104
------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 34 |00:00:00.01 | 11 |
| 1 | NESTED LOOPS | | 1 | 5 | 34 |00:00:00.01 | 11 |
| 2 | TABLE ACCESS BY INDEX ROWID| DEPARTMENTS | 1 | 1 | 1 |00:00:00.01 | 3 |
|* 3 | INDEX RANGE SCAN | DEPT_LOCATION_IX | 1 | 1 | 1 |00:00:00.01 | 2 |
| 4 | TABLE ACCESS BY INDEX ROWID| EMPLOYEES | 1 | 10 | 34 |00:00:00.01 | 8 |
|* 5 | INDEX RANGE SCAN | EMP_DEPARTMENT_IX | 1 | 10 | 34 |00:00:00.01 | 4 |
------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("D"."LOCATION_ID"=2500)
5 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
use_merge, leading(first, second) hint가 필요select /*+ gather_plan_statistics */ e.*, d.*
from hr.departments d, hr.employees e
where e.department_id = d.department_id;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
Plan hash value: 1343509718
------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | OMem | 1Mem | Used-Mem |
------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 106 |00:00:00.01 | 18 | 1 | | | |
| 1 | MERGE JOIN | | 1 | 106 | 106 |00:00:00.01 | 18 | 1 | | | |
| 2 | TABLE ACCESS BY INDEX ROWID| DEPARTMENTS | 1 | 27 | 27 |00:00:00.01 | 12 | 0 | | | |
| 3 | INDEX FULL SCAN | DEPT_ID_PK | 1 | 27 | 27 |00:00:00.01 | 6 | 0 | | | |
|* 4 | SORT JOIN | | 27 | 107 | 106 |00:00:00.01 | 6 | 1 | 22528 | 22528 |20480 (0)|
| 5 | TABLE ACCESS FULL | EMPLOYEES | 1 | 107 | 107 |00:00:00.01 | 6 | 1 | | | |
------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
filter("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
위의 실행계획은 두개의 집합을 만들고 키 컬럼을 가지고 merge 하는거다.
# first
select department_name, department_id
from hr.departments
order by department_id;
# second
select department_id, employee_id
from hr.employees
order by department_id;
select /*+ gather_plan_statistics leading(e,d) use_merge(d) */ e.*, d.*
from hr.departments d, hr.employees e
where e.department_id = d.department_id;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
Plan hash value: 3586199209
------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 106 |00:00:00.01 | 6 | | | |
| 1 | MERGE JOIN | | 1 | 106 | 106 |00:00:00.01 | 6 | | | |
| 2 | SORT JOIN | | 1 | 107 | 107 |00:00:00.01 | 4 | 15360 | 15360 |14336 (0)|
| 3 | TABLE ACCESS FULL| EMPLOYEES | 1 | 107 | 107 |00:00:00.01 | 4 | | | |
|* 4 | SORT JOIN | | 107 | 27 | 106 |00:00:00.01 | 2 | 2048 | 2048 | 2048 (0)|
| 5 | TABLE ACCESS FULL| DEPARTMENTS | 1 | 27 | 27 |00:00:00.01 | 2 | | | |
------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
filter("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
select /*+ gather_plan_statistics full(e) full(d) leading(d,e) use_merge(e) */ e.*, d.*
from hr.departments d, hr.employees e
where e.department_id = d.department_id;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
Plan hash value: 2202216887
------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 106 |00:00:00.01 | 6 | | | |
| 1 | MERGE JOIN | | 1 | 106 | 106 |00:00:00.01 | 6 | | | |
| 2 | SORT JOIN | | 1 | 27 | 27 |00:00:00.01 | 2 | 2048 | 2048 | 2048 (0)|
| 3 | TABLE ACCESS FULL| DEPARTMENTS | 1 | 27 | 27 |00:00:00.01 | 2 | | | |
|* 4 | SORT JOIN | | 27 | 107 | 106 |00:00:00.01 | 4 | 15360 | 15360 |14336 (0)|
| 5 | TABLE ACCESS FULL| EMPLOYEES | 1 | 107 | 107 |00:00:00.01 | 4 | | | |
------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
filter("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
select /*+ gather_plan_statistics leading(d,e) use_nl(e) */ e.*, d.*
from hr.departments d, hr.employees e
where e.department_id = d.department_id;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
Plan hash value: 1021246405
---------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
---------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 106 |00:00:00.01 | 39 | 5 |
| 1 | NESTED LOOPS | | 1 | 106 | 106 |00:00:00.01 | 39 | 5 |
| 2 | NESTED LOOPS | | 1 | 270 | 106 |00:00:00.01 | 24 | 5 |
| 3 | TABLE ACCESS FULL | DEPARTMENTS | 1 | 27 | 27 |00:00:00.01 | 11 | 5 |
|* 4 | INDEX RANGE SCAN | EMP_DEPARTMENT_IX | 27 | 10 | 106 |00:00:00.01 | 13 | 0 |
| 5 | TABLE ACCESS BY INDEX ROWID| EMPLOYEES | 106 | 4 | 106 |00:00:00.01 | 15 | 0 |
---------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
select /*+ gather_plan_statistics leading(e,d) use_nl(d) */ e.*, d.*
from hr.departments d, hr.employees e
where e.department_id = d.department_id;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
Plan hash value: 919050303
------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 106 |00:00:00.01 | 129 |
| 1 | NESTED LOOPS | | 1 | 106 | 106 |00:00:00.01 | 129 |
| 2 | NESTED LOOPS | | 1 | 107 | 106 |00:00:00.01 | 23 |
| 3 | TABLE ACCESS FULL | EMPLOYEES | 1 | 107 | 107 |00:00:00.01 | 13 |
|* 4 | INDEX UNIQUE SCAN | DEPT_ID_PK | 107 | 1 | 106 |00:00:00.01 | 10 |
| 5 | TABLE ACCESS BY INDEX ROWID| DEPARTMENTS | 106 | 1 | 106 |00:00:00.01 | 106 |
------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
use_hash(probe table 별칭), leading(build table, probe table) hint 사용swap_join_inputs : probe 테이블을 build 테이블로 변환하는 hintselect /*+ gather_plan_statistics leading(d,e) use_hash(e) */ e.*, d.*
from hr.departments d, hr.employees e
where e.department_id = d.department_id;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
Plan hash value: 2052257371
--------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | OMem | 1Mem | Used-Mem |
--------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 106 |00:00:00.01 | 64 | 11 | | | |
|* 1 | HASH JOIN | | 1 | 106 | 106 |00:00:00.01 | 64 | 11 | 1376K| 1376K| 1582K (0)|
| 2 | TABLE ACCESS FULL| DEPARTMENTS | 1 | 27 | 27 |00:00:00.01 | 2 | 0 | | | |
| 3 | TABLE ACCESS FULL| EMPLOYEES | 1 | 107 | 107 |00:00:00.01 | 11 | 0 | | | |
--------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
# build table, hash table
select department_name, department_id
from hr.departments;
# probe table
select department_id, employee_id
from hr.employees;
select /*+ gather_plan_statistics
leading(l,d,e)
use_hash(d)
use_hash(e)*/ e.*, d.*, l.*
from hr.departments d, hr.employees e, hr.locations l
where e.department_id = d.department_id
and d.location_id = l.location_id;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
Plan hash value: 2684174912
---------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | OMem | 1Mem | Used-Mem |
---------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 106 |00:00:00.01 | 17 | 2 | | | |
|* 1 | HASH JOIN | | 1 | 106 | 106 |00:00:00.01 | 17 | 2 | 932K| 932K| 1295K (0)|
|* 2 | HASH JOIN | | 1 | 27 | 27 |00:00:00.01 | 5 | 1 | 1031K| 1031K| 1290K (0)|
| 3 | TABLE ACCESS FULL| LOCATIONS | 1 | 23 | 23 |00:00:00.01 | 2 | 1 | | | |
| 4 | TABLE ACCESS FULL| DEPARTMENTS | 1 | 27 | 27 |00:00:00.01 | 2 | 0 | | | |
| 5 | TABLE ACCESS FULL | EMPLOYEES | 1 | 107 | 107 |00:00:00.01 | 11 | 0 | | | |
---------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
2 - access("D"."LOCATION_ID"="L"."LOCATION_ID")
select /*+ gather_plan_statistics
leading(d,e,l)
use_hash(e)
use_hash(l)
*/ e.*, d.*, l.*
from hr.departments d, hr.employees e, hr.locations l
where e.department_id = d.department_id
and d.location_id = l.location_id;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
Plan hash value: 1575956938
------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 106 |00:00:00.01 | 17 | | | |
|* 1 | HASH JOIN | | 1 | 106 | 106 |00:00:00.01 | 17 | 1025K| 1025K| 1296K (0)|
| 2 | TABLE ACCESS FULL | LOCATIONS | 1 | 23 | 23 |00:00:00.01 | 2 | | | |
|* 3 | HASH JOIN | | 1 | 106 | 106 |00:00:00.01 | 14 | 1376K| 1376K| 1538K (0)|
| 4 | TABLE ACCESS FULL| DEPARTMENTS | 1 | 27 | 27 |00:00:00.01 | 2 | | | |
| 5 | TABLE ACCESS FULL| EMPLOYEES | 1 | 107 | 107 |00:00:00.01 | 11 | | | |
------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("D"."LOCATION_ID"="L"."LOCATION_ID")
3 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
select /*+ gather_plan_statistics
leading(d,e,l)
use_hash(e)
use_hash(l)
swap_join_inputs(l)*/ e.*, d.*, l.*
from hr.departments d, hr.employees e, hr.locations l
where e.department_id = d.department_id
and d.location_id = l.location_id;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
Plan hash value: 1575956938
------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 106 |00:00:00.01 | 17 | | | |
|* 1 | HASH JOIN | | 1 | 106 | 106 |00:00:00.01 | 17 | 1025K| 1025K| 1284K (0)|
| 2 | TABLE ACCESS FULL | LOCATIONS | 1 | 23 | 23 |00:00:00.01 | 2 | | | |
|* 3 | HASH JOIN | | 1 | 106 | 106 |00:00:00.01 | 14 | 1376K| 1376K| 1501K (0)|
| 4 | TABLE ACCESS FULL| DEPARTMENTS | 1 | 27 | 27 |00:00:00.01 | 2 | | | |
| 5 | TABLE ACCESS FULL| EMPLOYEES | 1 | 107 | 107 |00:00:00.01 | 11 | | | |
------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("D"."LOCATION_ID"="L"."LOCATION_ID")
3 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
select /*+ gather_plan_statistics
leading(d,e,l)
use_hash(e)
use_hash(l)
no_swap_join_inputs(l)*/ e.*, d.*, l.*
from hr.departments d, hr.employees e, hr.locations l
where e.department_id = d.department_id
and d.location_id = l.location_id;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
Plan hash value: 3997756786
------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 106 |00:00:00.01 | 13 | | | |
|* 1 | HASH JOIN | | 1 | 106 | 106 |00:00:00.01 | 13 | 878K| 878K| 849K (0)|
|* 2 | HASH JOIN | | 1 | 106 | 106 |00:00:00.01 | 7 | 1376K| 1376K| 1500K (0)|
| 3 | TABLE ACCESS FULL| DEPARTMENTS | 1 | 27 | 27 |00:00:00.01 | 2 | | | |
| 4 | TABLE ACCESS FULL| EMPLOYEES | 1 | 107 | 107 |00:00:00.01 | 4 | | | |
| 5 | TABLE ACCESS FULL | LOCATIONS | 1 | 23 | 23 |00:00:00.01 | 5 | | | |
------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("D"."LOCATION_ID"="L"."LOCATION_ID")
2 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")