Optimizing Oracle Optimizer (2009년)
View Merging 0 0 97,090

by 구루비스터디 Transformation View Merging [2018.07.14]


View Merging

  • View를 Main Query 안으로 통합(Merge) 시킨다는 것을 의미한다.
  • (Inline) View와 Subquery를 적절히 Transformation 할 수 있다면 여러 개의 Query Block을 하나의 단일한 Query Block으로 통합할 수 있으며, Optimization 단계가 성공적으로 이루어질 가능성이 높아진다.


Simple View Merging

  • Simple View는 말 그대로 Group By 등의 복잡한 Operation을 포함하지 않는 단순한 View를 의미한다.



drop table t1 purge;
drop table t2 purge;
drop table t3 purge;

create table t1(c1 int, c2 char(10), c3 int);
create table t2(c1 int, c2 char(10), c3 int);
create table t3(c1 int, c2 char(10), c3 int);


create index t1_n1 on t1(c1);
create index t2_n1 on t2(c1);
create index t3_n1 on t3(c1);

create index t1_n2 on t1(c3);
create index t2_n2 on t2(c3);
create index t3_n2 on t3(c3);

-- Cost Based Query Transformation 비활성화
alter session set "_optimizer_cost_based_transformation" = off;
alter session set "_optimizer_push_pred_cost_based" = false;

-- Column c1 : Unique
-- Column c2 : 하나의 Distinct Count
-- Column c3 : 0~99의 100개의 Distinct Count
-- Table t1 : 10,000건
-- Table t2 : 1,000건
-- Table t3 : 100건

insert into t1 
select level, 'dummy', mod(level, 100) from dual
connect by level <= 10000
;

insert into t2
select level, 'dummy', mod(level, 100)  from dual
connect by level <= 1000
;

insert into t3
select level, 'dummy', mod(level, 100) from dual
connect by level <= 100
;


commit;

@gather t1
@gather t2
@gather t3


  • NO_MERGE Hint를 사용해 View Merging을 강제로 비활성화한 경우

select count(*) 
from (
select /*+ gather_plan_statistics */
  t1.c1, v.c2
from
  t1, 
  (select /*+ no_merge */ c1, c2 
    from t2 
    where c1 between 1 and 1000) v
where
  t1.c1 = v.c1
)
; 

@stat
-----------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation               | Name  | Starts | E-Rows | Cost (%CPU)| A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
-----------------------------------------------------------------------------------------------------------------------------------
|   1 |  SORT AGGREGATE         |       |      1 |      1 |            |      1 |00:00:00.01 |      31 |       |       |          |
|*  2 |   HASH JOIN             |       |      1 |   1000 |    10  (10)|   1000 |00:00:00.02 |      31 |  1517K|  1517K| 1251K (0)|
|   3 |    VIEW                 |       |      1 |   1000 |     2   (0)|   1000 |00:00:00.01 |       7 |       |       |          |
|*  4 |     INDEX FAST FULL SCAN| T2_N1 |      1 |   1000 |     2   (0)|   1000 |00:00:00.01 |       7 |       |       |          |
|   5 |    INDEX FAST FULL SCAN | T1_N1 |      1 |  10000 |     7   (0)|  10000 |00:00:00.05 |      24 |       |       |          |
-----------------------------------------------------------------------------------------------------------------------------------

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

   2 - access("T1"."C1"="V"."C1")
   4 - filter(("C1">=1 AND "C1"<=1000))

-- 3번 단께의 Veiw Operation이 View Merging이 실패했다는 것을 잘 보여준다.
-- View Merging이 실패한 경우 Oracle은 View에 대한 Optimization 작업과 전체 Query 에 대한 Optimization 작업을 별개로 처리하게 된다.
-- Oracle의 Optimization 작업은 Query Block 단위로 이루어지기 때문이다.
-- Inline View는 Index Range Scan, Main Query는 View 결과를 Index t1_n1에 대한 Index Fast Full Scan과 
-- Hash Join을 수행하게끔 Optimization이 이루어진다. (책과 다름)



  • View Merging이 성공적으로 이루어진 경우

select count(*)
from (
select /*+ gather_plan_statistics */
  t1.c1, v.c2
from
  t1, 
  (select c1, c2 
    from t2 
    where c1 between 1 and 1000) v
where
  t1.c1 = v.c1
)
; 

@stat
----------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation              | Name  | Starts | E-Rows | Cost (%CPU)| A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
----------------------------------------------------------------------------------------------------------------------------------
|   1 |  SORT AGGREGATE        |       |      1 |      1 |            |      1 |00:00:00.01 |      10 |       |       |          |
|*  2 |   HASH JOIN            |       |      1 |    999 |     6  (17)|   1000 |00:00:00.02 |      10 |  1517K|  1517K| 1337K (0)|
|*  3 |    INDEX FAST FULL SCAN| T2_N1 |      1 |   1000 |     2   (0)|   1000 |00:00:00.01 |       7 |       |       |          |
|*  4 |    INDEX RANGE SCAN    | T1_N1 |      1 |   1000 |     3   (0)|   1000 |00:00:00.01 |       3 |       |       |          |
----------------------------------------------------------------------------------------------------------------------------------

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

   2 - access("T1"."C1"="C1")
   3 - filter(("C1">=1 AND "C1"<=1000))
   4 - access("T1"."C1">=1 AND "T1"."C1"<=1000)

-- View Operation이 없어졌다. View Merging으로 인해 View가 없어졌다는 것을 의미한다.
-- 하나의 큰 변화는 Table t1, t2에 대해 모두 Index Range Scan을 사용하게 되었다는 것이다.(책과 다름)
-- 4번 단계에서 사용된 Predicate를 보면 Oracle에 의해 추가적으로 생성된 Predicate의 존재로 인해 
-- Table t2뿐만 아니라 Table t1에 대해서도 Index Range Scan을 사용할 수 있게 되었다.

-- Simple View Merging에 의해 다음과 같이 변형되었다는 것을 알 수 있다.

select
  t1.c1, t2.c2
from
  t1, t2
where
  t1.c1 = t2.c1 and
  t1.c1 between 1 and 1000 and
  t2.c1 between 1 and 1000
;

"데이터베이스 스터디모임" 에서 2009년에 "OPTIMIZING ORACLE OPTIMIZER " 도서를 스터디하면서 정리한 내용 입니다.

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

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

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

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