2.14_OT*_(Operator_Transformation)
2011.09.26 20:43
2.14 OT* ( Operator Transformation ) :
특정 연산자를 다른 연산자로 변환하라.
Oracle Transformer는 종종 개발자가 작성하지 않은 where 절을 추론하여 생성 한다.
그 이유는 transformer 가 특정 연산자를 다른 연산자로 변환하는 rule 을 가지고 있기 때문이다.
그 rule은 다음과 같다.
1.ALL연산자를 AND 조건으로 변환한다.
2.ANY 연산자를 OR 조건으로 변환한다.
3.IN 연산자를 OR 로 변환한다.
4.NOT 연산자를 제거한다.
5.BETWEEN 연산자를 >=AND <= 연산자로 변환한다.
다음은 예제 이다.
select e.employee_id,e.hire_date,e.job_id,d.department_name
from employee e,department d
where e.department_id = d.department_id
and e.salary > ALL( 2600,4400,13000);
e.salary < ALL( 2600,4400,13000); 조건의 2단계 변환과정은 거친다.
1단계
a.salary > 2600 and e.salary > 4400 and e.salary > 13000
2단계
3개의 조건이 AND 로 연결 제일 큰 값인 e.salary > 13000 조건만 만족하면 나머지 조건도 만족
=> 이와 같은 기능을 Filter Subsumtion
=> QT 는 지능적으로 ALL => AND 로 바꾸고 e.salary > 13000 를 access 하는 조건을 만든다
---------------------------------------------------+-----------------------------------+
| Id | Operation | Name | Rows | Bytes | Cost | Time |
---------------------------------------------------+-----------------------------------+
| 0 | SELECT STATEMENT | | | | 7 | |
| 1 | HASH JOIN | | 52 | 2288 | 7 | 00:00:01 |
| 2 | VIEW | index$_join$_002| 27 | 432 | 3 | 00:00:01 |
| 3 | HASH JOIN | | | | | |
| 4 | INDEX FAST FULL SCAN | DEPT_ID_PK | 27 | 432 | 1 | 00:00:01 |
| 5 | INDEX FAST FULL SCAN | DEPT_NAME_IDX | 27 | 432 | 1 | 00:00:01 |
| 6 | TABLE ACCESS FULL | EMPLOYEE | 54 | 1512 | 4 | 00:00:01 |
---------------------------------------------------+-----------------------------------+
Predicate Information:
----------------------
1 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
3 - access(ROWID=ROWID)
6 - filter("E"."SALARY">13000)
아래의 10053 Trace 정보에서 발견되는 특이한 점은 PM( predicate Move Around ) 의 자리에 Operator Transformation이 발생한다는 것이다. 이 CASE 이외에도 이런 제목에 맞지 않는 변환이 자주 나타난다. 미래의 버전에서는 각각의 Transformation 과정에 맞는 자리와 제목을 붙여주었으면 한다.
**************************
Predicate Move-Around (PM)
**************************
PM: PM bypassed: Outer query contains no views.
PM: PM bypassed: Outer query contains no views.
query block SEL$1 (#0) unchanged
FPD: Considering simple filter push in query block SEL$1 (#0)
"E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID" AND "E"."SALARY">2600 AND "E"."SALARY">4400 AND "E"."SALARY">13000
try to generate transitive predicate from check constraints for query block SEL$1 (#0)
finally: "E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID" AND "E"."SALARY">2600 AND "E"."SALARY">4400 AND "E"."SALARY">13000
1단계 변환으로 FPD가 수행 된 것을 알 수 있다.
아래의 trace 정보는 transformer의 작업이 아닌 phsicalOptization 고정이다.
*********************************
Number of join permutations tried: 2
*********************************
Consider using bloom filter between D[DEPARTMENT] and E[EMPLOYEE]
kkoBloomFilter: join (lcdn:27 rcdn:54 jcdn:52 limit:726)
Computing bloom ndv for creator:D[DEPARTMENT] ccdn:27.0 and user:E[EMPLOYEE] ucdn:53.7
kkopqComputeBloomNdv: predicate (bndv:11 ndv:11) and (bndv:27 ndv:27)
kkopqComputeBloomNdv: pred cnt:2 ndv:27 reduction:1
kkoBloomFilter: join ndv:0 reduction:0.502379 (limit:0.500000) rejected because distinct value ratio
(newjo-save) [0 1 ]
Trying or-Expansion on query block SEL$1 (#0)
Transfer Optimizer annotations for query block SEL$1 (#0)
id=1 frofand predicate="E"."SALARY">13000
위 trace 내용은 Join 진행 과정이며 and 조건이 정리되고 있다. Filter Subsumtion 이 발생되면 frofand 부분에 마지막 결과가 나타나게 된다. 이제 OT 의 또 다른 예제를 보자.
select
e.employee_id,e.first_name,e.last_name,e.email
from
employee e,department d
where
e.department_id = d.department_id
AND e.department_id in (00,20)
위 SQL 에서 IN 조건 역시 Transformer 가 OR 절로 변환하는 과정을 거친다.
--------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)|
--------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | | 2 (100)|
| 1 | NESTED LOOPS | | 1 | 1 | 34 | 2 (0)|
| 2 | INLIST ITERATOR | | 1 | | | |
| 3 | TABLE ACCESS BY INDEX ROWID| EMPLOYEE | 2 | 2 | 60 | 2 (0)|
|* 4 | INDEX RANGE SCAN | EMP_DEPARTMENT_IX | 2 | 2 | | 1 (0)|
|* 5 | INDEX UNIQUE SCAN | DEPT_ID_PK | 2 | 1 | 4 | 0 (0)|
--------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access(("E"."DEPARTMENT_ID"=0 OR "E"."DEPARTMENT_ID"=20))
5 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
filter(("D"."DEPARTMENT_ID"=0 OR "D"."DEPARTMENT_ID"=20))
위 plan 의 Predicate Information을 보면 IN을 OR조건으로 바뀌었음을 알수 있다.
또한 Transtice Predicate 기능에 의해서 ( D.DEPARTMENT = 10 OR D.DEPARTMENT_ID = 20 ) 조건이 추가로 생성 되었음을 알 수 있다.
참고로 All 연산자 대신에 Any 사용하였다면 WHere 절은 다음처럼 평가된다.
e.salary > ANY ( 2600,4400,13000 )
--> ( e.salary > 2600 OR e.salary > 4400 OR e.salary > 13000 )
또한 Not 연산자를 생성 했다면 오라클 Transformer 는 아래처럼 Not 연산자를 제거한다.
not ( e.salary <> 13000 or e.department_id is null )
--> e.salary = 13000 AND e.department_id is not null
위에서 설명한 5가지 변환에 대해서는 어자피 변환이 일어날 것이므로 미리 바꾸어 쓰라는 의도가 아니다.
다만 이러한 Rule 들을 모르는 상태에서 Plan 의 Predicate Information 을 본다면 당황스러울 수가있으므로 변환의 내부 원리를 설명한 것이다.
그러므로
1.ALL연산자를 AND 조건으로 변환한다.
2.ANY 연산자를 OR 조건으로 변환한다.
3.IN 연산자를 OR 로 변환한다.
4.NOT 연산자를 제거한다.
5.BETWEEN 연산자를 >=AND <= 연산자로 변환한다.
이 기본 Rule들은 반드시 기억하도록 하자.