2.15 PM(Predicate Move Around) : Where 조건을 다른 뷰에 이동시켜라

  • PM : 조건절을 다른 뷰 혹은 인라인뷰에 Copy하는 기능
  • 인라인뷰가 여러개있고 각각의 Where절에 공통적인 조건들이 있어야 한다고 가정.
    이런경우 모든 인라인뷰의 Where 절에 똑같은 조건들을 반복해서 사용해야 할까?
    {code:SQL
title= 예제borderStyle=solid}
CREATE INDEX DEPT_IX_01 ON department(department_id, location_id);

ALTER SESSION SET EVENTS '10053 trace name context forever, level 1';

SELECT /*+ gather_plan_statistics qb_name (v_outer) */
v1.*
FROM (SELECT /*+ qb_name (IV1) no_merge */ --QB_NAME 힌트를 통해 부여한 별명을 통해 정확하게 어떤 Operation이
e1.*, SQL Text의 어느 부분과 연결되어 있는지 직관적으로 파악
d1.location_id
FROM employee e1,
department d1
WHERE e1.department_id = d1.department_id
AND d1.department_id = 30
) v1,
(SELECT /*+ qb_name (IV2) no_merge */
AVG (salary) avg_sal_dept,
d2.department_id
FROM employee e2,
department d2,
location l2
WHERE e2.department_id = d2.department_id
AND l2.location_id = d2.location_id
GROUP BY d2.department_id
) v2_dept
WHERE v1.department_id = v2_dept.department_id
AND v1.salary > v2_dept.avg_sal_dept ;
--인라인뷰 V1에 de.department_id = 30이라는 조건이 있지만 V2에는 없다.
--PM기능으로 V1의 조건이 V2로 파고들어야한다.

ALTER SESSION SET EVENTS '10053 trace name context forever, level 1';

DROP INDEX DEPT_IX_01;

============
Plan Table
============
















-+







---+

IdOperationNameRowsBytesCostTime
















-+







---+

0SELECT STATEMENT1
1HASH JOIN1174100:00:01
2VIEW126100:00:01
3HASH GROUP BY1150
4NESTED LOOPS6900
5NESTED LOOPS180
6TABLE ACCESS BY INDEX ROWIDDEPARTMENT150
7INDEX UNIQUE SCANDEPT_ID_PK10
8INDEX UNIQUE SCANLOC_ID_PK23690
9TABLE ACCESS BY INDEX ROWIDEMPLOYEE6420
10INDEX RANGE SCANEMP_DEPARTMENT_IX60
11VIEW6888100:00:01
12NESTED LOOPS64560
13TABLE ACCESS BY INDEX ROWIDDEPARTMENT150
14INDEX UNIQUE SCANDEPT_ID_PK10
15TABLE ACCESS BY INDEX ROWIDEMPLOYEE64260
16INDEX RANGE SCANEMP_DEPARTMENT_IX60
















-+







---+
Predicate Information:





--
1 - access("V1"."DEPARTMENT_ID"="V2_DEPT"."DEPARTMENT_ID")
1 - filter("V1"."SALARY">"V2_DEPT"."AVG_SAL_DEPT")
7 - access("D2"."DEPARTMENT_ID"=30) --V2로 조건이 파고들어갔다.
8 - access("L2"."LOCATION_ID"="D2"."LOCATION_ID")
10 - access("E2"."DEPARTMENT_ID"=30) --V2로 조건이 파고들어갔다.
14 - access("D1"."DEPARTMENT_ID"=30)
16 - access("E1"."DEPARTMENT_ID"=30)

SELECT /*+ QB_NAME ("V_OUTER") */
"V1".*
FROM (SELECT /*+ NO_MERGE QB_NAME ("IV1") */
"E1".*,"D1"."LOCATION_ID" "LOCATION_ID"
FROM "TLO"."EMPLOYEE" "E1",
"TLO"."DEPARTMENT" "D1"
WHERE "E1"."DEPARTMENT_ID"=30 AND "D1"."DEPARTMENT_ID"=30) "V1",
(SELECT /*+ NO_MERGE QB_NAME ("IV2") */
AVG("E2"."SALARY") "AVG_SAL_DEPT",
"D2"."DEPARTMENT_ID" "DEPARTMENT_ID"
FROM "TLO"."EMPLOYEE" "E2",
"TLO"."DEPARTMENT" "D2",
"TLO"."LOCATION" "L2"
WHERE "E2"."DEPARTMENT_ID"=30 --V2로 조건이 파고들어갔다.
AND "L2"."LOCATION_ID"="D2"."LOCATION_ID"
AND "D2"."DEPARTMENT_ID"=30 --V2로 조건이 파고들어갔다.
GROUP BY "D2"."DEPARTMENT_ID") "V2_DEPT"
WHERE "V1"."DEPARTMENT_ID"="V2_DEPT"."DEPARTMENT_ID"
AND "V1"."SALARY">"V2_DEPT"."AVG_SAL_DEPT"


{code:SQL|title= 오라클은 어떤과정을 거쳐서 이작업을 수행하였을까? |borderStyle=solid}
**************************
Predicate Move-Around (PM)
**************************
PM:   Passed validity checks.                                --먼저 PM이 수행될 수 있는지 검사
PM: Added transitive pred "E1"."DEPARTMENT_ID"=30
 in query block IV1 (#2)
PM:   Pulled up predicate "V1"."DEPARTMENT_ID"=30            --V1에서 WHERE 조건 d1.department_id = 30을 바깥쪽 메인 쿼리로 이동시킨다.
 from query block IV1 (#2) to query block V_OUTER (#1)         (Predicate Pulled up)
PM: Added transitive pred "V2_DEPT"."DEPARTMENT_ID"=30
 in query block V_OUTER (#1)
PM:   Pushed down predicate "D2"."DEPARTMENT_ID"=30          --메인 쿼리로 옮겨진 Whee 조건을 v2에 복사한다.
 from query block V_OUTER (#1) to query block IV2 (#3)         (Predicate Pushed down)
PM:     PM bypassed: checking.                               --최종 결과에서 중복된 조건절이 존재하면 삭제한다.
 
  • PM이 발생되는 조건
    1. 뷰(혹은 인라인뷰)가 1개 혹은 그 이상 존재해야한다.(ex V1, V2)
    2. 인라인뷰내에 특정 조건이 존재하고 뷰의 바깥쪽에서 특정 조건을 사용한 컬럼으로 조인이 발생해야 한다.
    3. VIEW MERGE가 발생하지 않아야 한다.
    4. 파라미터 _PRED_MOVE_AROUND가 True로 지정이 되어 있어야 한다.|