컴퓨터뽀개버리기

[SQL] With 절 본문

꾸준히 보자/SQLP

[SQL] With 절

그순간을기억해 2024. 4. 18. 23:42
반응형

 

  • oracle 9i부터 사용 가능
  • 쿼리 내에서 한 번 이상 사용되는 집합을 미리 임시 테이블로 저장
  • 문장 안에서 반복 사용이 가능
    • 다른 쿼리에서는 사용이 불가함

 

사용하는 이유

사실 With절 없어도 Inline뷰를 사용하면 쿼리는 가능하나

상황에 따라 같은 테이블을 여러 번 반복 읽어야되고, 코드가 복잡해져 유지보수가 용이하지 못한 단점이 있다.

이 때, With절을 사용하면 반복 접근이 필요한 뷰를 With절에 선언해두고 아래 쿼리에서 사용하면 되어 활용도가 높아진다.

 

 

사용 예시

with agg_emp as (select deptno, round(avg(sal)) as avg_sal
                    from emp
                    group by deptno)
select a.empno, b.avg_sal
from emp a
    ,agg_emp b
where a.deptno = b.deptno
and a.sal > b.avg_sal;

with 절에서 만들 테이블 명을 명시하고, 뒤에 select절을 붙이면 된다.

, 로 연결해서 여러 개의 임시 테이블도 만들 수 있다.

WITH agg_emp AS (SELECT deptno, ROUND(AVG(sal)) AS avg_sal 
                   FROM emp 
                  GROUP BY deptno) 
   , avg_emp AS (SELECT ROUND(AVG(avg_sal)) avg_tot
                   FROM agg_emp) 

 

위 쿼리는 Inline View로도 충분히 가능하다.

그렇다면 성능적인 면에서는 어떤 차이가 있는지 확인해보자.

실행계획 비교하기(Inline view VS With)

두 개 실행 계획을 뽑아봤는데 동일한 플랜이 나오는 걸 확인했다.

여기서 알 수 있는 점은

with절에서 정의한 테이블을 한 번만 사용하면 Temp Table을 만들지 않고 옵티마이저가 inline와 동일하게 실행한다는 것이다.

--- With 절 & inline view 절
----------------------------------------------------------------------------------------------
| Id  | Operation                    | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |               |     1 |    51 |     7  (29)| 00:00:01 |
|   1 |  MERGE JOIN                  |               |     1 |    51 |     7  (29)| 00:00:01 |
|   2 |   TABLE ACCESS BY INDEX ROWID| EMP           |    14 |   350 |     2   (0)| 00:00:01 |
|   3 |    INDEX FULL SCAN           | EMP_DEPTNO_IX |    14 |       |     1   (0)| 00:00:01 |
|*  4 |   FILTER                     |               |       |       |            |          |
|*  5 |    SORT JOIN                 |               |     3 |    78 |     5  (40)| 00:00:01 |
|   6 |     VIEW                     |               |     3 |    78 |     4  (25)| 00:00:01 |
|   7 |      SORT GROUP BY           |               |     3 |    21 |     4  (25)| 00:00:01 |
|   8 |       TABLE ACCESS FULL      | EMP           |    14 |    98 |     3   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------

 

그렇다면 두 번 접근하면 실행계획은?

Inline View

--- 부서원 급여 합계 평균보다 높은 부서
select deptno, sum(sal) as sum
from emp
group by deptno
having sum(sal) > (select avg(sum(sal))
										from emp
										group by deptno);
-----------------------------------------------------------------------------
| Id  | Operation            | Name | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |      |     1 |     7 |     4  (25)| 00:00:01 |
|*  1 |  FILTER              |      |       |       |            |          |
|   2 |   HASH GROUP BY      |      |     1 |     7 |     4  (25)| 00:00:01 |
|   3 |    TABLE ACCESS FULL | EMP  |    14 |    98 |     3   (0)| 00:00:01 |
|   4 |   SORT AGGREGATE     |      |     1 |     7 |     4  (25)| 00:00:01 |
|   5 |    SORT GROUP BY     |      |     1 |     7 |     4  (25)| 00:00:01 |
|   6 |     TABLE ACCESS FULL| EMP  |    14 |    98 |     3   (0)| 00:00:01 |
-----------------------------------------------------------------------------

EMP 테이블을 2번 Access한 것을 확인할 수 있다.

  1. [4-6] EMP 테이블을 group by 하고 집계한 결과에 집계함수를 사용하면서 sort aggregate 절이 나타남
  2. [1-3] having 절에서 filter하여 결과를 반환

With 절

with sum_sal as (select deptno, sum(sal) as sum
                    from emp
                    group by deptno)
select * 
from sum_sal
where sum > (select avg(sum) from sum_sal);

----------------------------------------------------------------------------------------------------------------------
| Id  | Operation                                | Name                      | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                         |                           |     3 |    78 |     8  (13)| 00:00:01 |
|   1 |  TEMP TABLE TRANSFORMATION               |                           |       |       |            |          |
|   2 |   LOAD AS SELECT (CURSOR DURATION MEMORY)| SYS_TEMP_0FD9D7747_184A40 |       |       |            |          |
|   3 |    HASH GROUP BY                         |                           |     3 |    21 |     4  (25)| 00:00:01 |
|   4 |     TABLE ACCESS FULL                    | EMP                       |    14 |    98 |     3   (0)| 00:00:01 |
|*  5 |   VIEW                                   |                           |     3 |    78 |     2   (0)| 00:00:01 |
|   6 |    TABLE ACCESS FULL                     | SYS_TEMP_0FD9D7747_184A40 |     3 |    21 |     2   (0)| 00:00:01 |
|   7 |    SORT AGGREGATE                        |                           |     1 |    13 |            |          |
|   8 |     VIEW                                 |                           |     3 |    39 |     2   (0)| 00:00:01 |
|   9 |      TABLE ACCESS FULL                   | SYS_TEMP_0FD9D7747_184A40 |     3 |    21 |     2   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------------------

Temp Table이라는 구문이 나타났고, EMP테이블은 한번만 엑세스함을 알 수 있다.

그 이후에는 SYS_TEMP이란 것을 활용해서 쿼리 수행이 이뤄진다.

아까와는 달리 실행계획이 다르게 나타남을 확인할 수 있다.

 

성능적인 부분(주의 사항)

위 예시는 deptno 로 group by하기 때문에 테이블의 크기가 작아서 with 절을 사용하는데 전혀 문제가 없다.

 

만약 여기서 임시 테이블의 크기가 커진다면?

  • 임시 테이블을 저장할 메모리 공간이 부족하면 디스크 I/O가 발생하여 오히려 성능에 영향을 줄 수 있다.
  • 인라인 뷰로 작성하면 여러 조인과 최적화 작업으로 해결할 수 있어 튜닝에 자유도가 높아진다.

무차별적인 남용은 지양해야된다!

 

힌트 ( materialize )

그리고 이때 힌트를 사용해서 TEMP Table을 만들지 여부를 조정할 수 있다.

/*+ materialize */ -- 임시테이블 생성
/*+ inline */ -- 임시테이블을 생성하지 않고 인라인뷰로 수행

정리

  • 문장 안에서 With 절의 Subquery 사용 횟수에 따라 실행계획이 달라진다.
    • 두 번 이상 사용되면 → 임시 테이블 생성
    • 한 번 사용하면 Inline View 와 동일함
  • Temp Table 생성 여부를 유도하는 힌트도 존재
  • With 절의 임시 테이블 형식의 사용은 Physical I/O를 동반할 수 있으므로 그 크기가 크지 않는 경우 유리
반응형

'꾸준히 보자 > SQLP' 카테고리의 다른 글

[SQL] OUTER JOIN 정리!  (0) 2024.04.16
[SQL] SQL 파싱 - 소프트 파싱/하드 파싱  (0) 2024.04.15