2.14 OT* (Operator Transformation) : 특정 연산자를 다른 연산자로 변환하라

  • Oracle Transformer는 종종 개발자가 작성하지 않은 Where 절을 추론하여 생성 하곤 한다
  • 그 이유는 Transformer가 특정 연산자를 만나면 다른 연산자로 변환하는 RULE을 가지고 있기 때문이다.
  • Operator Transformation 발생시 사용되는 몇 가지 RULE이 있는데 다음과 같다.
    1. ALL 연산자를 AND로 변환한다.
    2. ANY 연산자를 OR로 변환한다
    3. IN 연산자를 OR로 변환한다
    4. NOT 연산자를 제거한다
    5. BETWEEN 연산자를 >= AND <= 연산자로 변환한다.
{code:SQLtitle= ALL 연산자를 AND로 변환borderStyle=solid}
ALTER SESSION SET EVENTS '10053 trace name context forever, level 1';

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);

ALTER SESSION SET EVENTS '10053 trace name context off';
============
Plan Table
============













--+







---+

IdOperationNameRowsBytesCostTime













--+







---+

0SELECT STATEMENT4
1MERGE JOIN532226300:00:01
2TABLE ACCESS BY INDEX ROWIDDEPARTMENT273780
3INDEX FULL SCANDEPT_ID_PK270
4SORT JOIN541512300:00:01
5TABLE ACCESS FULLEMPLOYEE541512200:00:01













--+







---+
Predicate Information:





--
4 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
4 - filter("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
5 - filter("E"."SALARY">13000)


* e.salary > ALL (2600, 4400 , 13000) 조건은 다음과 같이 2단계의 변환과정을 거친다
** 1단계변환 :
옵티마이져는 ALL조건을 아래와 같이변환시킨다.
e.salary > 2600 AND e.salary >4400 AND e.salary > 13000
** 2단계변환:
3개의 조건이 AND로 연결되어 있으므로 제일 큰 값인 e.salary > 13000 조건만 만족하면 나머지
2개의 조건도 만족한다. 따라서 e.salary > 13000조건만 남게 된다.
이런 기능을 Filter Subsumtion이라고 한다.
이와같이 Query Transformer는 매우 지능적이어서 All조건을 And조건으로 바꾼다음 모든 조건을 만족하는 집합인
e.SALARY > 13000집합만을 Access 하는 SQL을 만들게 되는 것이다.|
|{code:SQL|title= IN 연산자를 OR로 변환 |borderStyle=solid}
explain plan for
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 (10, 20);

select * from table(dbms_xplan.display);
---------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name              | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |                   |     3 |    99 |     1 (100)| 00:00:01 |
|   1 |  NESTED LOOPS                 |                   |     3 |    99 |     0   (0)| 00:00:01 |
|   2 |   INLIST ITERATOR             |                   |       |       |            |          |
|   3 |    TABLE ACCESS BY INDEX ROWID| EMPLOYEE          |     3 |    90 |     0   (0)| 00:00:01 |
|*  4 |     INDEX RANGE SCAN          | EMP_DEPARTMENT_IX |     3 |       |     0   (0)| 00:00:01 |
|*  5 |   INDEX UNIQUE SCAN           | DEPT_ID_PK        |     1 |     3 |     0   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------

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

4 - access("E"."DEPARTMENT_ID"=10 OR "E"."DEPARTMENT_ID"=20)
5 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")
filter("D"."DEPARTMENT_ID"=10 OR "D"."DEPARTMENT_ID"=20)

  • IN을 OR 조건으로 바꾸었음을 알 수 있다
  • Transitive Predicale 기능에 의해서 (D.DEPARTMENT_ID=10 OR D.DEPARTMENT_ID=20) 조건이 추가로 생성|
{code:SQLtitle= ANY 연산자를 OR로 변환borderStyle=solid}
e.salary > ANY (2600, 4400, 13000)
--> (e.salary > 2600 OR e.salary > 4400 OR e.salary > 13000)
{code}
{code:SQL
title= NOT연산자를 제거borderStyle=solid}
not (e.salary <> 13000 or e.department_id is null)
--> e.salary = 13000 AND e.department_id IS NOT NULL
{code}