# 요약
  ■ Pushing Subquery
push_subq

■ view merging
merge
no_merge

1. simple view merging
2. complex view merging

■ 조인 조건 pushdown
no_push_pred

■ Bloom Filter

 

 


 


■ Pushing Subquery
- 실행계획상 가능한 앞 단계에서 서브쿼리의 필터링을 먼저 처리함으로써 다음 수행 단계로 넘어가는 행 수를 줄일 수 있는 기능
- unnesting 되지 않은 서브쿼리의 처리 순서를 제어하는 기능
- Hint : push_subq

# unnest 방식

HR@ora11g> select /*+ gather_plan_statistics */ e.*, d.*
           from employees e, departments d
           where e.department_id = d.department_id
           and exists (select 'x'
                       from locations
                       where location_id = d.location_id
                       and city = 'London');


HR@ora11g> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

----------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                       | Name              | Starts | E-Rows | A-Rows |   A-Time   | Buffers | OMem | 1Mem | Used-Mem |
----------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                |                   |      1 |        |      1 |00:00:00.01 |       8 |      |      |          |
|   1 |  NESTED LOOPS                   |                   |      1 |     15 |      1 |00:00:00.01 |       8 |      |      |          |
|   2 |   NESTED LOOPS                  |                   |      1 |     40 |      1 |00:00:00.01 |       7 |      |      |          |
|   3 |    NESTED LOOPS                 |                   |      1 |      4 |      1 |00:00:00.01 |       5 |      |      |          |
|   4 |     SORT UNIQUE                 |                   |      1 |      1 |      1 |00:00:00.01 |       2 | 2048 | 2048 | 2048  (0)|
|   5 |      TABLE ACCESS BY INDEX ROWID| LOCATIONS         |      1 |      1 |      1 |00:00:00.01 |       2 |      |      |          |
|*  6 |       INDEX RANGE SCAN          | LOC_CITY_IX       |      1 |      1 |      1 |00:00:00.01 |       1 |      |      |          |
|   7 |     TABLE ACCESS BY INDEX ROWID | DEPARTMENTS       |      1 |      4 |      1 |00:00:00.01 |       3 |      |      |          |
|*  8 |      INDEX RANGE SCAN           | DEPT_LOCATION_IX  |      1 |      4 |      1 |00:00:00.01 |       2 |      |      |          |
|*  9 |    INDEX RANGE SCAN             | EMP_DEPARTMENT_IX |      1 |     10 |      1 |00:00:00.01 |       2 |      |      |          |
|  10 |   TABLE ACCESS BY INDEX ROWID   | EMPLOYEES         |      1 |      4 |      1 |00:00:00.01 |       1 |      |      |          |
----------------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   6 - access("CITY"='London')
   8 - access("LOCATION_ID"="D"."LOCATION_ID")
   9 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")


> query trasformation 작동 > 조인방식
> 서브쿼리 LOC_CITY_IX > DEPT_LOCATION_IX > EMP_DEPARTMENT_IX
> 근데 SORT UNIQUE 왜 나옴? > LOC_CITY_IX : nonunique index라서 중복값 있을까바 optimizer가 불안했던 듯?



↓ JOIN 방식으로 변경

HR@ora11g> select /*+ gather_plan_statistics */ e.*, d.*
           from employees e, departments d, locations l
           where e.department_id = d.department_id
           and d.location_id = l.location_id
           and city = 'London';


HR@ora11g> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

--------------------------------------------------------------------------------------------------------------
| Id  | Operation                      | Name              | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
--------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |                   |      1 |        |      1 |00:00:00.01 |       9 |
|   1 |  NESTED LOOPS                  |                   |      1 |     15 |      1 |00:00:00.01 |       9 |
|   2 |   NESTED LOOPS                 |                   |      1 |     40 |      1 |00:00:00.01 |       8 |
|   3 |    NESTED LOOPS                |                   |      1 |      4 |      1 |00:00:00.01 |       6 |
|   4 |     TABLE ACCESS BY INDEX ROWID| LOCATIONS         |      1 |      1 |      1 |00:00:00.01 |       3 |
|*  5 |      INDEX RANGE SCAN          | LOC_CITY_IX       |      1 |      1 |      1 |00:00:00.01 |       2 |
|   6 |     TABLE ACCESS BY INDEX ROWID| DEPARTMENTS       |      1 |      4 |      1 |00:00:00.01 |       3 |
|*  7 |      INDEX RANGE SCAN          | DEPT_LOCATION_IX  |      1 |      4 |      1 |00:00:00.01 |       2 |
|*  8 |    INDEX RANGE SCAN            | EMP_DEPARTMENT_IX |      1 |     10 |      1 |00:00:00.01 |       2 |
|   9 |   TABLE ACCESS BY INDEX ROWID  | EMPLOYEES         |      1 |      4 |      1 |00:00:00.01 |       1 |
--------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   5 - access("CITY"='London')
   7 - access("D"."LOCATION_ID"="L"."LOCATION_ID")
   8 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")


> 5번 buffer 2번? : INDEX RANGE SCAN = 1+1 scan = buffer pinning 미작동 
> sort 작업은 하지 않았으니 이게 더 효율



# filter 방식 수행 (no_unnest 적용)

HR@ora11g> select /*+ gather_plan_statistics */ e.*, d.*
           from employees e, departments d
           where e.department_id = d.department_id
           and exists (select /*+ no_unnest */ 'x'
                       from locations
                       where location_id = d.location_id
                       and city = 'London');


HR@ora11g> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

----------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name        | Starts | E-Rows | A-Rows |   A-Time   | Buffers | OMem | 1Mem | Used-Mem |
----------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |             |      1 |        |      1 |00:00:00.01 |      24 |       |       |        |
|*  1 |  FILTER                       |             |      1 |        |      1 |00:00:00.01 |      24 |       |       |        |
|   2 |   MERGE JOIN                  |             |      1 |    106 |    106 |00:00:00.01 |      10 |       |       |        |
|   3 |    TABLE ACCESS BY INDEX ROWID| DEPARTMENTS |      1 |     27 |     27 |00:00:00.01 |       4 |       |       |        |
|   4 |     INDEX FULL SCAN           | DEPT_ID_PK  |      1 |     27 |     27 |00:00:00.01 |       2 |       |       |        |
|*  5 |    SORT JOIN                  |             |     27 |    107 |    106 |00:00:00.01 |       6 | 15360 | 15360 |14336  (0)|
|   6 |     TABLE ACCESS FULL         | EMPLOYEES   |      1 |    107 |    107 |00:00:00.01 |       6 |       |       |        |
|*  7 |   TABLE ACCESS BY INDEX ROWID | LOCATIONS   |      7 |      1 |      1 |00:00:00.01 |      14 |       |       |        |
|*  8 |    INDEX UNIQUE SCAN          | LOC_ID_PK   |      7 |      1 |      7 |00:00:00.01 |       7 |       |       |        |
----------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter( IS NOT NULL)
   5 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
       filter("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
   7 - filter("CITY"='London')
   8 - access("LOCATION_ID"=:B1)


> 메인쿼리 Full scan - MERGE JOIN

 

 

 

# push_subq : unnest가 수행 안되었을 경우 서브쿼리를 먼저 수행하자

HR@ora11g> select /*+ gather_plan_statistics */ e.*, d.*
           from employees e, departments d
           where e.department_id = d.department_id
           and exists (select /*+ no_unnest push_subq */ 'x'
                       from locations
                       where location_id = d.location_id
                       and city = 'London');


HR@ora11g> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

--------------------------------------------------------------------------------------------------------------
| Id  | Operation                      | Name              | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
--------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |                   |      1 |        |      1 |00:00:00.01 |      24 |
|   1 |  NESTED LOOPS                  |                   |      1 |     13 |      1 |00:00:00.01 |      24 |
|   2 |   NESTED LOOPS                 |                   |      1 |     13 |      1 |00:00:00.01 |      23 |
|*  3 |    TABLE ACCESS FULL           | DEPARTMENTS       |      1 |      1 |      1 |00:00:00.01 |      21 |
|*  4 |     TABLE ACCESS BY INDEX ROWID| LOCATIONS         |      7 |      1 |      1 |00:00:00.01 |      14 |
|*  5 |      INDEX UNIQUE SCAN         | LOC_ID_PK         |      7 |      1 |      7 |00:00:00.01 |       7 |
|*  6 |    INDEX RANGE SCAN            | EMP_DEPARTMENT_IX |      1 |     10 |      1 |00:00:00.01 |       2 |
|   7 |   TABLE ACCESS BY INDEX ROWID  | EMPLOYEES         |      1 |     10 |      1 |00:00:00.01 |       1 |
--------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - filter( IS NOT NULL)
   4 - filter("CITY"='London')
   5 - access("LOCATION_ID"=:B1)
   6 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")


> outer : DEPARTMENTS
  inner : EMP_DEPARTMENT_IX

> 3 ~ 5 수행하는 SQL문
HR@ora11g> select *
           from departments d
           where exists (select 'x'
                         from locations
                         where location_id = d.location_id
                         and city = 'London')
           and location_id is not null;        --> d.location_id에 not null 제약조건이 없기 때문






■ view merging
- view를 해체하여 메인쿼리와 통합한다.
- Hint : merge, no_merge

# merge

HR@ora11g> select /*+ gather_plan_statistics */ *
           from (select * from employees where manager_id = 145) e,
                (select * from departments where location_id = 2500) d
           where e.department_id = d.department_id;


HR@ora11g> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

------------------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name             | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |                  |      1 |        |      6 |00:00:00.01 |       7 |
|   1 |  NESTED LOOPS                 |                  |      1 |      1 |      6 |00:00:00.01 |       7 |
|   2 |   NESTED LOOPS                |                  |      1 |      6 |      6 |00:00:00.01 |       5 |
|   3 |    TABLE ACCESS BY INDEX ROWID| DEPARTMENTS      |      1 |      1 |      1 |00:00:00.01 |       3 |
|*  4 |     INDEX RANGE SCAN          | DEPT_LOCATION_IX |      1 |      1 |      1 |00:00:00.01 |       2 |
|*  5 |    INDEX RANGE SCAN           | EMP_MANAGER_IX   |      1 |      6 |      6 |00:00:00.01 |       2 |
|*  6 |   TABLE ACCESS BY INDEX ROWID | EMPLOYEES        |      6 |      1 |      6 |00:00:00.01 |       2 |
------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   4 - access("LOCATION_ID"=2500)
   5 - access("MANAGER_ID"=145)
   6 - filter("EMPLOYEES"."DEPARTMENT_ID"="DEPARTMENTS"."DEPARTMENT_ID")

 



# no_merge

HR@ora11g> select /*+ gather_plan_statistics */ *
           from (select /*+ no_merge */ * from employees where manager_id = 145) e,
                (select /*+ no_merge */ * from departments where location_id = 2500) d
           where e.department_id = d.department_id;


HR@ora11g> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

---------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name             | Starts | E-Rows | A-Rows |   A-Time   | Buffers | OMem | 1Mem | Used-Mem |
---------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |                  |      1 |        |      6 |00:00:00.01 |       6 |    |        |          |
|*  1 |  HASH JOIN                    |                  |      1 |      1 |      6 |00:00:00.01 |       6 |  1033K|  1033K|  350K (0)|
|   2 |   VIEW                        |                  |      1 |      1 |      1 |00:00:00.01 |       2 |    |        |          |
|   3 |    TABLE ACCESS BY INDEX ROWID| DEPARTMENTS      |      1 |      1 |      1 |00:00:00.01 |       2 |    |        |          |
|*  4 |     INDEX RANGE SCAN          | DEPT_LOCATION_IX |      1 |      1 |      1 |00:00:00.01 |       1 |    |        |          |
|   5 |   VIEW                        |                  |      1 |      6 |      6 |00:00:00.01 |       4 |    |        |          |
|   6 |    TABLE ACCESS BY INDEX ROWID| EMPLOYEES        |      1 |      6 |      6 |00:00:00.01 |       4 |    |        |          |
|*  7 |     INDEX RANGE SCAN          | EMP_MANAGER_IX   |      1 |      6 |      6 |00:00:00.01 |       2 |    |        |          |
---------------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
   4 - access("LOCATION_ID"=2500)
   7 - access("MANAGER_ID"=145)



↓ merge 수행 동일

HR@ora11g> select /*+ gather_plan_statistics */ *
           from employees e, departments d
           where e.department_id = d.department_id
           and d.location_id = 2500
           and e.manager_id = 145;


HR@ora11g> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

------------------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name             | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |                  |      1 |        |      6 |00:00:00.01 |       7 |
|   1 |  NESTED LOOPS                 |                  |      1 |      1 |      6 |00:00:00.01 |       7 |
|   2 |   NESTED LOOPS                |                  |      1 |      6 |      6 |00:00:00.01 |       5 |
|   3 |    TABLE ACCESS BY INDEX ROWID| DEPARTMENTS      |      1 |      1 |      1 |00:00:00.01 |       3 |
|*  4 |     INDEX RANGE SCAN          | DEPT_LOCATION_IX |      1 |      1 |      1 |00:00:00.01 |       2 |
|*  5 |    INDEX RANGE SCAN           | EMP_MANAGER_IX   |      1 |      6 |      6 |00:00:00.01 |       2 |
|*  6 |   TABLE ACCESS BY INDEX ROWID | EMPLOYEES        |      6 |      1 |      6 |00:00:00.01 |       2 |
------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   4 - access("D"."LOCATION_ID"=2500)
   5 - access("E"."MANAGER_ID"=145)
   6 - filter("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")


> 처음부터 6개 행 추출
> DEPT_LOCATION_IX + EMP_MANAGER_IX 조인 안되는건데? > Cartesian Product (카티시안 곱) 발생

 

 

↓  e.manager_id 인덱스 스캔을 막아보자.

HR@ora11g> select /*+ gather_plan_statistics */ *
           from employees e, departments d
           where e.department_id = d.department_id
           and d.location_id = 2500
           and to_number(e.manager_id) = 145;


HR@ora11g> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

-------------------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name              | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |                   |      1 |        |      6 |00:00:00.01 |       7 |
|   1 |  NESTED LOOPS                 |                   |      1 |      1 |      6 |00:00:00.01 |       7 |
|   2 |   NESTED LOOPS                |                   |      1 |     10 |     34 |00:00:00.01 |       5 |
|   3 |    TABLE ACCESS BY INDEX ROWID| DEPARTMENTS       |      1 |      1 |      1 |00:00:00.01 |       3 |
|*  4 |     INDEX RANGE SCAN          | DEPT_LOCATION_IX  |      1 |      1 |      1 |00:00:00.01 |       2 |
|*  5 |    INDEX RANGE SCAN           | EMP_DEPARTMENT_IX |      1 |     10 |     34 |00:00:00.01 |       2 |
|*  6 |   TABLE ACCESS BY INDEX ROWID | EMPLOYEES         |     34 |      1 |      6 |00:00:00.01 |       2 |
-------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   4 - access("D"."LOCATION_ID"=2500)
   5 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
   6 - filter(TO_NUMBER(TO_CHAR("E"."MANAGER_ID"))=145)


> 34행 데이터에서 필터링으로 6개 추출, 버퍼피닝 덕분에 버퍼가 적게 나왔을 뿐 비효율

 

 

 

1. simple view merging
- view, inline view 내부에 group by, distinct 등이 없는 view를 의미한다.
- simple view를 만나면 view를 해체하고 메인쿼리와 통합하는 작업을 수행한다.

# no_merge

HR@ora11g> select /*+ gather_plan_statistics */ *
           from employees e, (select /*+ no_merge */ * from departments where department_id = 20) d
           where e.department_id = d.department_id;


HR@ora11g> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

-------------------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name              | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |                   |      1 |        |      2 |00:00:00.01 |       6 |
|   1 |  NESTED LOOPS                 |                   |      1 |     10 |      2 |00:00:00.01 |       6 |
|   2 |   VIEW                        |                   |      1 |      1 |      1 |00:00:00.01 |       2 |
|   3 |    TABLE ACCESS BY INDEX ROWID| DEPARTMENTS       |      1 |      1 |      1 |00:00:00.01 |       2 |
|*  4 |     INDEX UNIQUE SCAN         | DEPT_ID_PK        |      1 |      1 |      1 |00:00:00.01 |       1 |
|   5 |   TABLE ACCESS BY INDEX ROWID | EMPLOYEES         |      1 |     10 |      2 |00:00:00.01 |       4 |
|*  6 |    INDEX RANGE SCAN           | EMP_DEPARTMENT_IX |      1 |     10 |      2 |00:00:00.01 |       2 |
-------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   4 - access("DEPARTMENT_ID"=20)
   6 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")




# merging

HR@ora11g> select /*+ gather_plan_statistics */ *
           from employees e, (select * from departments where department_id = 20) d
           where e.department_id = d.department_id;


HR@ora11g> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

------------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name              | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |                   |      1 |        |      2 |00:00:00.01 |       6 |
|   1 |  NESTED LOOPS                |                   |      1 |      2 |      2 |00:00:00.01 |       6 |
|   2 |   TABLE ACCESS BY INDEX ROWID| DEPARTMENTS       |      1 |      1 |      1 |00:00:00.01 |       2 |
|*  3 |    INDEX UNIQUE SCAN         | DEPT_ID_PK        |      1 |      1 |      1 |00:00:00.01 |       1 |
|   4 |   TABLE ACCESS BY INDEX ROWID| EMPLOYEES         |      1 |      2 |      2 |00:00:00.01 |       4 |
|*  5 |    INDEX RANGE SCAN          | EMP_DEPARTMENT_IX |      1 |      2 |      2 |00:00:00.01 |       2 |
------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - access("DEPARTMENT_ID"=20)
   5 - access("E"."DEPARTMENT_ID"=20)

> d.department_id = 20 값이 정해져 있으니 조인 필요없다 -> 카티시안 곱 발생


↓ Transformation

HR@ora11g> select /*+ gather_plan_statistics */ *
           from employees e, departments d
           where e.department_id = 20
           and d.department_id = 20;

> 의도적으로 카티시안 곱 발생




2. complex view merging
- group by 나 distinct 가 있으면 view, inline view를 merging 한다.

alter session set "_complex_view_merging" = true; (9i 기본값)

- complex view 안에 union, union all, intersect, minus, connect by, rownum,
  group by 없는 전체 집계값을 구현하는 그룹함수, 분석함수가 포함되어 있을 경우 merging 할 수 없다.

HR@ora11g> select /*+ gather_plan_statistics */ d.department_id, department_name, e.avg_sal
           from departments d, (select department_id, avg(salary) avg_sal
                                from employees
                                group by department_id) e
           where d.department_id = e.department_id
           and d.location_id = 1800;


HR@ora11g> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

-----------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                      | Name              | Starts | E-Rows | A-Rows |   A-Time   | Buffers | OMem | 1Mem | Used-Mem |
-----------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |                   |      1 |        |      1 |00:00:00.01 |       4 |     |       |          |
|   1 |  HASH GROUP BY                 |                   |      1 |      1 |      1 |00:00:00.01 |       4 | 810K|   810K|  425K (0)|
|   2 |   NESTED LOOPS                 |                   |      1 |     10 |      2 |00:00:00.01 |       4 |     |       |          |
|   3 |    NESTED LOOPS                |                   |      1 |     10 |      2 |00:00:00.01 |       3 |     |       |          |
|   4 |     TABLE ACCESS BY INDEX ROWID| DEPARTMENTS       |      1 |      1 |      1 |00:00:00.01 |       2 |     |       |          |
|*  5 |      INDEX RANGE SCAN          | DEPT_LOCATION_IX  |      1 |      1 |      1 |00:00:00.01 |       1 |     |       |          |
|*  6 |     INDEX RANGE SCAN           | EMP_DEPARTMENT_IX |      1 |     10 |      2 |00:00:00.01 |       1 |     |       |          |
|   7 |    TABLE ACCESS BY INDEX ROWID | EMPLOYEES         |      2 |     10 |      2 |00:00:00.01 |       1 |     |       |          |
-----------------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   5 - access("D"."LOCATION_ID"=1800)
   6 - access("D"."DEPARTMENT_ID"="DEPARTMENT_ID")


- HASH GROUP BY : group by 사용



↓  JOIN

HR@ora11g> select /*+ gather_plan_statistics */ d.department_id, d.department_name, avg(e.salary)
           from departments d, employees e
           where d.department_id = e.department_id
           and d.location_id = 1800
           group by d.department_id, d.department_name;


HR@ora11g> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

-----------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                      | Name              | Starts | E-Rows | A-Rows |   A-Time   | Buffers | OMem | 1Mem | Used-Mem |
-----------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |                   |      1 |        |      1 |00:00:00.01 |       4 |     |       |          |
|   1 |  HASH GROUP BY                 |                   |      1 |      1 |      1 |00:00:00.01 |       4 | 850K|   850K|  425K (0)|
|   2 |   NESTED LOOPS                 |                   |      1 |     10 |      2 |00:00:00.01 |       4 |     |       |          |
|   3 |    NESTED LOOPS                |                   |      1 |     10 |      2 |00:00:00.01 |       3 |     |       |          |
|   4 |     TABLE ACCESS BY INDEX ROWID| DEPARTMENTS       |      1 |      1 |      1 |00:00:00.01 |       2 |     |       |          |
|*  5 |      INDEX RANGE SCAN          | DEPT_LOCATION_IX  |      1 |      1 |      1 |00:00:00.01 |       1 |     |       |          |
|*  6 |     INDEX RANGE SCAN           | EMP_DEPARTMENT_IX |      1 |     10 |      2 |00:00:00.01 |       1 |     |       |          |
|   7 |    TABLE ACCESS BY INDEX ROWID | EMPLOYEES         |      2 |     10 |      2 |00:00:00.01 |       1 |     |       |          |
-----------------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   5 - access("D"."LOCATION_ID"=1800)
   6 - access("D"."DEPARTMENT_ID"="E"."DEPARTMENT_ID")






■ 조인 조건 pushdown
- 조인조건절을 뷰 쿼리 블록안으로 넣어서 조인수행 시 드라이빙 테이블에 읽은 조인컬럼값을 inner쪽 뷰 쿼리 블록내에서 참조할 수 있도록 하는 기능

# no_merge

HR@ora11g> select /*+ gather_plan_statistics */ d.department_id, department_name, e.avg_sal
           from departments d, (select /*+ no_merge */ department_id, avg(salary) avg_sal
                                from employees
                                group by department_id) e
           where d.department_id = e.department_id
           and d.location_id = 1800;


HR@ora11g> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

---------------------------------------------------------------------------------------------------------------
| Id  | Operation                       | Name              | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
---------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                |                   |      1 |        |      1 |00:00:00.01 |       5 |
|   1 |  NESTED LOOPS                   |                   |      1 |      1 |      1 |00:00:00.01 |       5 |
|   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 |   VIEW PUSHED PREDICATE         |                   |      1 |      1 |      1 |00:00:00.01 |       2 |
|*  5 |    FILTER                       |                   |      1 |        |      1 |00:00:00.01 |       2 |
|   6 |     SORT AGGREGATE              |                   |      1 |      1 |      1 |00:00:00.01 |       2 |
|   7 |      TABLE ACCESS BY INDEX ROWID| EMPLOYEES         |      1 |     10 |      2 |00:00:00.01 |       2 |
|*  8 |       INDEX RANGE SCAN          | EMP_DEPARTMENT_IX |      1 |     10 |      2 |00:00:00.01 |       1 |
---------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - access("D"."LOCATION_ID"=1800)
   5 - filter(COUNT(*)>0)
   8 - access("DEPARTMENT_ID"="D"."DEPARTMENT_ID")  --> 인라인뷰안에 그룹바이 자리에 위치


- VIEW PUSHED PREDICATE : Transformation
- FILTER : 반복

- no_merge : merge가 안되었을 시 재연용으로 사용했을 뿐
- and 조건이 없었다면 잘 쓴 SQL문
- 메인where절 -> group by 대신 사용
- inner : employees

 

 

 

■ Bloom Filter
- hash join 시 probe(후행) 집합에서 조인에 참여하는 건수를 줄임으로써 join 시간을 단축시키는 알고리즘

 

# no_merge no_push_pred : 조인조건을 인라인뷰에 푸쉬하지마라

HR@ora11g> select /*+ gather_plan_statistics */ d.department_id, department_name, e.avg_sal
           from departments d, (select /*+ no_merge no_push_pred*/ department_id, avg(salary) avg_sal
                                from employees
                                group by department_id) e
           where d.department_id = e.department_id
           and d.location_id = 1800;


HR@ora11g> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

---------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name             | Starts | E-Rows | A-Rows |   A-Time   | Buffers | OMem | 1Mem | Used-Mem |
---------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |                  |      1 |        |      1 |00:00:00.01 |       8 |    |        |          |
|*  1 |  HASH JOIN                    |                  |      1 |      1 |      1 |00:00:00.01 |       8 |  1114K|  1114K|  245K (0)|
|   2 |   JOIN FILTER CREATE          | :BF0000          |      1 |      1 |      1 |00:00:00.01 |       2 |    |        |          |
|   3 |    TABLE ACCESS BY INDEX ROWID| DEPARTMENTS      |      1 |      1 |      1 |00:00:00.01 |       2 |    |        |          |
|*  4 |     INDEX RANGE SCAN          | DEPT_LOCATION_IX |      1 |      1 |      1 |00:00:00.01 |       1 |    |        |          |
|   5 |   VIEW                        |                  |      1 |     11 |      1 |00:00:00.01 |       6 |    |        |          |
|   6 |    HASH GROUP BY              |                  |      1 |     11 |      1 |00:00:00.01 |       6 |   894K|   894K|  680K (0)|
|   7 |     JOIN FILTER USE           | :BF0000          |      1 |    107 |      2 |00:00:00.01 |       6 |    |        |          |
|*  8 |      TABLE ACCESS FULL        | EMPLOYEES        |      1 |    107 |      2 |00:00:00.01 |       6 |    |        |          |
---------------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("D"."DEPARTMENT_ID"="E"."DEPARTMENT_ID")
   4 - access("D"."LOCATION_ID"=1800)
   8 - filter(SYS_OP_BLOOM_FILTER(:BF0000,"DEPARTMENT_ID"))


- SYS_OP_BLOOM_FILTER -> Bloom Filter

- build : DEPARTMENTS
  probe : EMPLOYEES : M쪽집합

- JOIN FILTER CREATE
- JOIN FILTER USE
>> 알고리즘