오라클 성능 고도화 원리와 해법 II (2010년)
집합 연산을 조인으로 변환 0 0 3,707

by 구루비 쿼리변환 INTERSECT MINUS [2010.05.14]


Intersect 나 Minus 같은 집합(set) 연산을 조인 형태로 변환하는 것을 말한다.
아래는 deptno = 10에 속한 사원들의 job,mgr 을 제외시키고, 나머지 job,mgr 집합만 찾는 쿼리다.


SQL> create table emp as select * from scott.emp;

테이블이 생성되었습니다.

SQL> select job, mgr from emp
  2  minus
  3  select job, mgr from emp
  4  where  deptno = 10 ;

Execution Plan
----------------------------------------------------------
Plan hash value: 3686975449

----------------------------------------------------------------------------
| Id  | Operation           | Name | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |      |    14 |   362 |     8  (63)| 00:00:01 |
|   1 |  MINUS              |      |       |       |            |          |
|   2 |   SORT UNIQUE       |      |    14 |   266 |     4  (25)| 00:00:01 |
|   3 |    TABLE ACCESS FULL| EMP  |    14 |   266 |     3   (0)| 00:00:01 |
|   4 |   SORT UNIQUE       |      |     3 |    96 |     4  (25)| 00:00:01 |
|*  5 |    TABLE ACCESS FULL| EMP  |     3 |    96 |     3   (0)| 00:00:01 |
----------------------------------------------------------------------------

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

   5 - filter("DEPTNO"=10)

각각 Sort Unique 연산을 수행한후 Minus연산을 수행하는 것을 볼수 있다.
아래와 같이 _convert_set_to_join 파라미터를 true로 설정하고 다시 실행계획을 확인


SQL> alter session set "_convert_set_to_join" = true;

세션이 변경되었습니다.

SQL>
SQL> select job, mgr from emp
  2  minus
  3  select job, mgr from emp
  4  where  deptno = 10 ;

Execution Plan
----------------------------------------------------------
Plan hash value: 4030040631

----------------------------------------------------------------------------
| Id  | Operation           | Name | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |      |    13 |   663 |     8  (25)| 00:00:01 |
|   1 |  HASH UNIQUE        |      |    13 |   663 |     8  (25)| 00:00:01 |
|*  2 |   HASH JOIN ANTI    |      |    13 |   663 |     7  (15)| 00:00:01 |
|   3 |    TABLE ACCESS FULL| EMP  |    14 |   266 |     3   (0)| 00:00:01 |
|*  4 |    TABLE ACCESS FULL| EMP  |     3 |    96 |     3   (0)| 00:00:01 |
----------------------------------------------------------------------------

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

   2 - access(SYS_OP_MAP_NONNULL("JOB")=SYS_OP_MAP_NONNULL("JOB") AND
              SYS_OP_MAP_NONNULL("MGR")=SYS_OP_MAP_NONNULL("MGR"))
   4 - filter("DEPTNO"=10)

해시 ANTI조인을 수행하고 중복 값을 제거하기 위해 Hash Unique연산을 수행하는 것을 볼수 있음
아래와 같은 형태로 쿼리변환이 일어난 것임


SQL> select distinct job, mgr from emp e
  2  where  not exists (
  3    select 'x' from emp
  4    where  deptno = 10
  5    and    sys_op_map_nonnull(job) = sys_op_map_nonnull(e.job)
  6    and    sys_op_map_nonnull(mgr) = sys_op_map_nonnull(e.mgr)
  7  ) ;

Execution Plan
----------------------------------------------------------
Plan hash value: 4030040631

----------------------------------------------------------------------------
| Id  | Operation           | Name | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |      |    13 |   663 |     8  (25)| 00:00:01 |
|   1 |  HASH UNIQUE        |      |    13 |   663 |     8  (25)| 00:00:01 |
|*  2 |   HASH JOIN ANTI    |      |    13 |   663 |     7  (15)| 00:00:01 |
|   3 |    TABLE ACCESS FULL| EMP  |    14 |   266 |     3   (0)| 00:00:01 |
|*  4 |    TABLE ACCESS FULL| EMP  |     3 |    96 |     3   (0)| 00:00:01 |
----------------------------------------------------------------------------

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

   2 - access(SYS_OP_MAP_NONNULL("JOB")=SYS_OP_MAP_NONNULL("E"."JOB")
              AND SYS_OP_MAP_NONNULL("MGR")=SYS_OP_MAP_NONNULL("E"."MGR"))
   4 - filter("DEPTNO"=10)

sys_op_map_nonull함수는 비공식적인 함수지만 가끔유용하게 사용할수 있음
null값끼리 '=' 비교 (null = null) 하면 false이지만 가끔 true가 되도록 처리해야 하는 경우가 있고,
그럴때 sys_op_map_nonull함수를 사용하면 됨
위에서는 job 과 mgr이 null허용 컬럼이기 때문에 우와 같은 처리가 일어났음

문서에 대하여

"코어 오라클 데이터베이스 스터디모임" 에서 2010년에 "오라클 성능 고도화 원리와 해법 II " 도서를 스터디하면서 정리한 내용 입니다.

- 강좌 URL : http://www.gurubee.net/lecture/3235

- 구루비 강좌는 개인의 학습용으로만 사용 할 수 있으며, 다른 웹 페이지에 게재할 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^^

- 구루비 강좌는 서비스 제공을 위한 목적이나, 학원 홍보, 수익을 얻기 위한 용도로 사용 할 수 없습니다.

댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입