예문을 통해 WHERE를 쓰는 경우와 HAVING을 쓰는 경우의 차이에 대해 알아 보도록 하겠습니다. 어느 방법이 효율이 좋을지 미리 추측을 해보시죠^^;;;
저의 경우 통계 정보를 보기 위해 set autotrace 를 사용했으며 이 부분에 대한 내용은 Oracle 튜닝 강좌를 참고하시기 바랍니다.
참고로 아래 myemp 테이블은 10만건 정도의 레코드를 가지고 있으며 deptno는 외래키로서 인덱스가 걸려 있습니다.
SQL> set autotrace on
SQL> set timing on
아래 질의는 MTEMP 테이블의 데이터를 DEPTNO 별로 그룹핑 하는데 DEPTNO가 10번인 부서원들의 수를 COUNT하는 질의 입니다.
SQL> select deptno, count(*)
2 from myemp
3 group by deptno
4 having deptno = 10;
선택된 레코드가 없습니다.
경 과: 00:00:00.05
Execution Plan
-----------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 FILTER
2 1 SORT (GROUP BY)
3 2 TABLE ACCESS (FULL) OF 'MYEMP'
이 경우에는 Table을 FULL SCAN한 후 GROUP BY를 한 후 deptno가 10인 것을 찾기 위해 FILTER를 사용 했습니다. 통계정보는 아래와 같습니다.
Statistics
-----------------------------------------------------
0 recursive calls
0 db block gets
304 consistent gets
275 physical reads
0 redo size
282 bytes sent via SQL*Net to client
372 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
0 rows processed
이 번에는 having 대신 where절을 이용하여 같은 결과를 만들어 보도록 하겠습니다.
SQL> select deptno, count(*)
2 from myemp
3 where deptno = 10
4 group by deptno;
선택된 레코드가 없습니다.
경 과: 00:00:00.04
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 SORT (GROUP BY)
2 1 INDEX (RANGE SCAN) OF 'IDX_MYEMP_DEPTNO' (NON-UNIQUE)
이 경우에는 DEPTNO의 인덱스를 이용하여 부분 검색을 통해 deptno가 10인 데이터를 꺼낸 후 GROUP BY를 시켜 count(*)를 구하였습니다.
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
59 consistent gets
30 physical reads
1748 redo size
282 bytes sent via SQL*Net to client
372 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
0 rows processed
두 번째의 경우(where를 이용하는 경우)가 deptno에 인덱스가 걸려 있는 경우 약간 효율이 앞선 다고 할 수 있습니다. 시간도 쬐금 앞서구요… 하지만 무조건은 절대 아닙니다. 때에 따라서는 데이터를 먼저 집계를 낸 후 집계된 데이터를 조건을 주어 비교하는 경우도 있으니까요.. 특히 집계된 값이 어떠하다라고 비교 할려면 having구만을 사용해야 합니다. 아래처럼 말입니다.
SQL> select deptno, count(*)
2 from myemp
3 group by deptno
4 having sum(sal) > 2000;
DEPTNO COUNT(*)
---------- ----------
30 49002
40 16533
2 개의 행이 선택되었습니다.
경 과: 00:00:00.07
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 FILTER
2 1 SORT (GROUP BY)
3 2 TABLE ACCESS (FULL) OF 'MYEMP'
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
304 consistent gets
300 physical reads
0 redo size
482 bytes sent via SQL*Net to client
503 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
2 rows processed
저의 경우 통계 정보를 보기 위해 set autotrace 를 사용했으며 이 부분에 대한 내용은 Oracle 튜닝 강좌를 참고하시기 바랍니다.
참고로 아래 myemp 테이블은 10만건 정도의 레코드를 가지고 있으며 deptno는 외래키로서 인덱스가 걸려 있습니다.
SQL> set autotrace on
SQL> set timing on
아래 질의는 MTEMP 테이블의 데이터를 DEPTNO 별로 그룹핑 하는데 DEPTNO가 10번인 부서원들의 수를 COUNT하는 질의 입니다.
SQL> select deptno, count(*)
2 from myemp
3 group by deptno
4 having deptno = 10;
선택된 레코드가 없습니다.
경 과: 00:00:00.05
Execution Plan
-----------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 FILTER
2 1 SORT (GROUP BY)
3 2 TABLE ACCESS (FULL) OF 'MYEMP'
이 경우에는 Table을 FULL SCAN한 후 GROUP BY를 한 후 deptno가 10인 것을 찾기 위해 FILTER를 사용 했습니다. 통계정보는 아래와 같습니다.
Statistics
-----------------------------------------------------
0 recursive calls
0 db block gets
304 consistent gets
275 physical reads
0 redo size
282 bytes sent via SQL*Net to client
372 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
0 rows processed
이 번에는 having 대신 where절을 이용하여 같은 결과를 만들어 보도록 하겠습니다.
SQL> select deptno, count(*)
2 from myemp
3 where deptno = 10
4 group by deptno;
선택된 레코드가 없습니다.
경 과: 00:00:00.04
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 SORT (GROUP BY)
2 1 INDEX (RANGE SCAN) OF 'IDX_MYEMP_DEPTNO' (NON-UNIQUE)
이 경우에는 DEPTNO의 인덱스를 이용하여 부분 검색을 통해 deptno가 10인 데이터를 꺼낸 후 GROUP BY를 시켜 count(*)를 구하였습니다.
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
59 consistent gets
30 physical reads
1748 redo size
282 bytes sent via SQL*Net to client
372 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
0 rows processed
두 번째의 경우(where를 이용하는 경우)가 deptno에 인덱스가 걸려 있는 경우 약간 효율이 앞선 다고 할 수 있습니다. 시간도 쬐금 앞서구요… 하지만 무조건은 절대 아닙니다. 때에 따라서는 데이터를 먼저 집계를 낸 후 집계된 데이터를 조건을 주어 비교하는 경우도 있으니까요.. 특히 집계된 값이 어떠하다라고 비교 할려면 having구만을 사용해야 합니다. 아래처럼 말입니다.
SQL> select deptno, count(*)
2 from myemp
3 group by deptno
4 having sum(sal) > 2000;
DEPTNO COUNT(*)
---------- ----------
30 49002
40 16533
2 개의 행이 선택되었습니다.
경 과: 00:00:00.07
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 FILTER
2 1 SORT (GROUP BY)
3 2 TABLE ACCESS (FULL) OF 'MYEMP'
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
304 consistent gets
300 physical reads
0 redo size
482 bytes sent via SQL*Net to client
503 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
2 rows processed
'DB' 카테고리의 다른 글
[SGA튜닝] SQL문장의 메모리 사용량 확인 (0) | 2006.07.16 |
---|---|
[SQL튜닝]EXISTS 와 DISTINCT (0) | 2006.07.16 |
오라클에서 제공하는 작업 스케쥴링 사용하기 (0) | 2006.07.16 |
nls_database 세팅보기(캐릭터 셋 보기) (0) | 2006.01.06 |
캐릭터셋 변경 (0) | 2006.01.06 |