메뉴 건너뛰기

bysql.net

2.14_OT*_(Operator_Transformation)

ms 2011.09.26 21:13 조회 수 : 2239

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들은 반드시 기억하도록 하자.