4_03 뷰 Merging

Hi·2026년 7월 21일

(1) 뷰 Merging 이란?

< 쿼리1 > (머징 전 - 인라인 뷰)
select *
from   (select * from emp  where job = 'SALESMAN') a,
       (select * from dept where loc = 'CHICAGO') b
where  a.deptno = b.deptno


< 쿼리2 > (머징 후 - 펼쳐진 형태)
select *
from   emp a, dept b
where  a.deptno = b.deptno
and    a.job = 'SALESMAN'
and    b.loc = 'CHICAGO'

쿼리1의 뷰 쿼리 블록은 액세스 쿼리 블록과의 머지 과정을 거쳐 쿼리2와 같은 형태로 변환되는데, 이를 '뷰 Merging'이라고 한다.

(힌트: merge, no_merge)

(2) 단순 뷰 Merging

조건절과 조인문만을 포함하는 단순 뷰는 no_merge 힌트를 사용하지 않는 한 언제든 Merging이 일어난다.

반면 group by 절이나 distinct 연산을 포함하는 복합 뷰는 파라미터 설정 또는 힌트 사용에 의해서만 뷰 Merging이 가능하다.

또한, 집합 연산자, connect by, rownum 등을 포함하는복합 뷰는 아예 뷰 Merging이 불가능하다.

(3) 복합 뷰 Merging

_complex_view_merging 파라미터를 true로 설정하더라도 아래 항목들을 포함하는 복합뷰는 Merging 될 수 없다.

  • 집합(set) 연산자 (union, union all, intersect, minus)
  • connect by절
  • ROWNUM pseudo 컬럼
  • select-list에 집계 함수 (avg, count, max, min, sum) 사용 : group by 없이 전체를 집계하는 경우를 말함
  • 분석 함수
select d.dname, avg_sal_dept
from   dept d,
       (select deptno, avg(sal) avg_sal_dept
        from   emp
        group by deptno) e
where  d.deptno = e.deptno
and    d.loc = 'CHICAGO'


-- 복합 뷰 머징 후 변환된 쿼리
select d.dname, avg(sal)
from   dept d, emp e
where  d.deptno = e.deptno
and    d.loc = 'CHICAGO'
group by d.rowid, d.dname

-- 뷰 Merging이 일어난다면 두 쿼리는 똑같이 아래 실행계획을 사용한다.

Execution Plan
--------------------------------------------------------------------------
0        SELECT STATEMENT Optimizer=ALL_ROWS (Cost=5 Card=1 Bytes=28)
1    0    HASH (GROUP BY) (Cost=5 Card=1 Bytes=28)
2    1     TABLE ACCESS (BY INDEX ROWID) OF 'EMP' (TABLE)
3    2      NESTED LOOPS (Cost=4 Card=5 Bytes=140)
4    3       TABLE ACCESS (FULL) OF 'DEPT' (TABLE) (Cost=1 Card=5 Bytes=25)
5    3       INDEX (RANGE SCAN) OF 'EMP_IDX' (INDEX) (Cost=0 Card=5)

위 쿼리가 뷰 Merging을 통해 얻을 수 있는 이점은, dept.loc = 'CHICAGO'인 데이터만 선택해서 조인하고, 조인에 성공한 집합만 group by 한다는 데에 있다.

(5) Merging 되지 않는 뷰의 처리방식

뷰 Merging을 시행했을 때 오히려 비용이 더 증가한다고 판단되거나 부정확한 결과집합이 만들어질 가능성이 있을 때 옵티마이저는 뷰 Merging을 포기한다.

뷰 Merging이 이루어지지 않았을 땐 2차적으로 조건절 Pushing을 시도한다.

하지만 이마저도 실패한다면 뷰 쿼리 블록을 개별적으로 최적화하고, 거기서 생성된 서브플랜을 전체 실행계획을 생성하는 데 사용한다.

NO_MERGE 시 실행계획에 VIEW 오퍼레이션이 나타난다!

-- order by 절을 추가하고 다시 수행해보자
select /*+ leading(d) use_nl(e) */ *
from   dept d,
       (select /*+ NO_MERGE */ * from emp ORDER BY ENAME) e
where  e.deptno = d.deptno


Call      Count  CPU Time  Elapsed Time    Disk    Query   Current   Rows
-------   -----  --------  ------------    ----    -----   -------   ----
Parse         1     0.000         0.002       0        0         0      0
Execute       1     0.000         0.000       0        0         0      0
Fetch         2     0.000         0.000       0        7         0     14
-------   -----  --------  ------------    ----    -----   -------   ----
Total         4     0.000         0.003       0        7         0     14


Rows    Row Source Operation
-----   ---------------------------------------------------------------
   14   NESTED LOOPS (cr=7 pr=0 pw=0 time=169 us)
    4    TABLE ACCESS FULL DEPT (cr=4 pr=0 pw=0 time=87 us)
   14    VIEW (cr=3 pr=0 pw=0 time=208 us)
   56     SORT ORDER BY (cr=3 pr=0 pw=0 time=255 us)
   14      TABLE ACCESS FULL EMP (cr=3 pr=0 pw=0 time=61 us)

0개의 댓글