본문 바로가기

카테고리 없음

ORACLE CONCATERNATION v1.0


ORACLE CONCATERNATION

 

from

 

1.     ORACLE CONCATERNATION

CONCATERNATION OR 연산의 효율적인 이용을 위해 사용된다. A라는 테이블이 있고 이에 대해 B, C라는 조건이 OR 로 있을 때 B,C 조건이 같은 컬럼에 대한 조건이면 FULL SCAN 이 나타날 확률이 높아진다. B,C 라는 조건이 결합인덱스로 묶여 있는 경우에는 INDEX FULL SCAN 을 할 가능성이 높다. 하지만 CONCATERNATION 이 일어나면 OR 로 묶여 있는 각 조건에 대하여 각각의 조건을 만족하는 합집합을 구한다. 표현하자면

(A=B) U (A=C) 이런 느낌이다. 이는 다시 말해 중복값이 제거된다는 이야기다.

 

장점은 위와 같이 처리했을 때 효율적인 엑세스(인덱스 등을 이용한)가 가능한 상황일 때 이며 단점은 오브젝트를 중복 접근한다는 것이다.

 

힌트의 사용방법은 OR 를 사용한 쿼리에서 /*+ use_concat */ 힌트를 사용한다.

 

CONCATERNATION 으로 풀리면 나타나는 특징이 있다. 그것은 술어부가 마지막 술어부에서 WHERE 절 술어부 방향으로 체크된다는 것이다.

2.     CONCATERNATION 예제

select /*+ use_concat */first_name,salary,department_id

from employees

where department_id >80

or (department_id = 80 and salary > 10000)

or salary > 12000

/

 

위의 쿼리를 수행하면 총 20건이 나오며 실행플랜은 아래와 같다.

 

Execution Plan

----------------------------------------------------------

Plan hash value: 3551705692

 

--------------------------------------------------------------------------------------------------

| Id  | Operation                    | Name              | Rows  | Bytes | Cost (%CPU)| Time     |

--------------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT             |                   |    73 |  1022 |     8   (0)| 00:00:01 |

|   1 |  CONCATENATION               |                   |       |       |            |          |

|   2 |   TABLE ACCESS BY INDEX ROWID| EMPLOYEES         |    11 |   154 |     2   (0)| 00:00:01 |

|*  3 |    INDEX RANGE SCAN          | EMP_DEPARTMENT_IX |    11 |       |     1   (0)| 00:00:01 |

|*  4 |   TABLE ACCESS FULL          | EMPLOYEES         |    20 |   280 |     3   (0)| 00:00:01 |

|*  5 |   TABLE ACCESS FULL          | EMPLOYEES         |    42 |   588 |     3   (0)| 00:00:01 |

--------------------------------------------------------------------------------------------------

 

Predicate Information (identified by operation id):

---------------------------------------------------

 

   3 - access("DEPARTMENT_ID">80)

   4 - filter("DEPARTMENT_ID"=80 AND "SALARY">10000 AND LNNVL("DEPARTMENT_ID">80))

   5 - filter("SALARY">12000 AND (LNNVL("DEPARTMENT_ID"=80) OR LNNVL("SALARY">10000)) AND

              LNNVL("DEPARTMENT_ID">80))

 

위의 술어부 정보를 보면 5 -> 4 -> 3 순으로 사용되었음을 알 수 있다. 술어부를 보면 LNNVL 이 있는데 이에 대한 설명은 생략하겠다. (오라클이 내부적으로 사용하는 함수이며

UNKNOWN 이나 FALSE 일 때 TRUE 가 되는 함수이다. 이가 의미하바는 LNNVL 에 정의 되어 있는 집합군을 제거한다느 것이다. 이는 UNION을 사용한 것과 동일하다 : 중복값제거)

 

위의 값이 중복값제거한 결과라는 것은 아래의 쿼리를 수행해 확인할 수 있다.

 

select count(*) from

(select * from employees where department_id >80

union all

select * from employees where department_id = 80 and salary > 10000

union all

select * from employees where salary > 12000)

/

 

COUNT(*)

----------

        25

 

-------------------------------------------------------------------------------------------

| Id  | Operation             | Name              | Rows  | Bytes | Cost (%CPU)| Time     |

-------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT      |                   |     1 |       |     2   (0)| 00:00:01 |

|   1 |  SORT AGGREGATE       |                   |     1 |       |            |          |

|   2 |   VIEW                |                   |   321 |       |     2   (0)| 00:00:01 |

|   3 |    UNION-ALL PARTITION|                   |       |       |            |          |

|*  4 |     INDEX RANGE SCAN  | EMP_DEPARTMENT_IX |    11 |    33 |     1   (0)| 00:00:01 |

|*  5 |     INDEX RANGE SCAN  | EMP_IX2           |    22 |   154 |     1   (0)| 00:00:01 |

|*  6 |     INDEX FULL SCAN   | EMP_IX2           |    59 |   236 |     1   (0)| 00:00:01 |

-------------------------------------------------------------------------------------------

 

select count(*) from

(select * from employees where department_id >80

union

select * from employees where department_id = 80 and salary > 10000

union

select * from employees where salary > 12000)

/

 

COUNT(*)

----------

        20

 

-----------------------------------------------------------------------------------------------------

| Id  | Operation                       | Name              | Rows  | Bytes | Cost (%CPU)| Time     |

-----------------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT                |                   |     1 |       |    11  (28)| 00:00:01 |

|   1 |  SORT AGGREGATE                 |                   |     1 |       |            |          |

|   2 |   VIEW                          |                   |    92 |       |    11  (28)| 00:00:01 |

|   3 |    SORT UNIQUE                  |                   |    92 |  6256 |    11  (82)| 00:00:01 |

|   4 |     UNION-ALL                   |                   |       |       |            |          |

|   5 |      TABLE ACCESS BY INDEX ROWID| EMPLOYEES         |    11 |   748 |     2   (0)| 00:00:01 |

|*  6 |       INDEX RANGE SCAN          | EMP_DEPARTMENT_IX |    11 |       |     1   (0)| 00:00:01 |

|*  7 |      TABLE ACCESS FULL          | EMPLOYEES         |    22 |  1496 |     3   (0)| 00:00:01 |

|*  8 |      TABLE ACCESS FULL          | EMPLOYEES         |    59 |  4012 |     3   (0)| 00:00:01 |

-----------------------------------------------------------------------------------------------------

 

위에서의 20건은 OR 를 사용했을 때와 동일함을 알 수 있다.