2013년 8월 14일 수요일

ORACLE SQL EXISTS 와 DISTINCT

EXISTS DISTINCT

오라클자바커뮤니티에서 설립한 오엔제이프로그래밍 실무교육센터

(신입사원채용무료교육, 오라클SQL, 튜닝, 힌트,자바프레임워크, 안드로이드, 아이폰, 닷넷)  
 
SELECT 문장에서 DISTINCT를 사용하는 이유는 중복된 행을 제거 하기 위해서 입니다. 이를 위해 오라클은 SORT를 수행 하며 소트를 위한 시간, 메모리 또는 디스크 공간이 필요 할 수도 있습니다. 그러니깐 가급적이면 사용 안 하는 것이 좋습니다. 추출되는 데이터가 순서에 의해 출력되지 않아도 된다면 아래의 경우처럼 EXISTS를 사용하는 것이 훨씬 효율적 입니다. 예제를 통해 이해 하도록 하겠습니다. 실제 비용은 1/10 정도로 줄게 됩니다.
:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> 
SQL> set autotrace on
SQL> select distinct c.name
  2  from s_customer c, s_ord o
  3  where c.id = o.customer_id;
 
NAME
--------------------------------------------------
Beisbol Si!
Big John's Sports Emporium
:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />Delhi Sports
Futbol Sonora
Hamada Sport
Kam's Sporting Goods
Kuhn's Sports
Muench Sports
OJ Atheletics
Ojibway Retail
Sportique
 
NAME
--------------------------------------------------
Unisports
Womansport
 
13 개의 행이 선택되었습니다.
 
   : 00:00:00.03
 
Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   SORT (UNIQUE)
   2    1     NESTED LOOPS
   3    2       TABLE ACCESS (FULL) OF 'S_ORD'
   4    2       TABLE ACCESS (BY INDEX ROWID) OF 'S_CUSTOMER'
   5    4         INDEX (UNIQUE SCAN) OF 'S_CUSTOMER_ID_PK' (UNIQUE)
 
이 경우엔 S_ORD 테이블을 전체 스캔 한 데이터와 S_CUSTOMER 테이블의 데이터를 UNIQUE 인덱스를 이용하여 가져온 후 ROWIDD로 찾은 데이터와 비교하여 같은 아이디의 데이터가 있으면 추출하고 아니면 반복하는 구조를 가집니다. 그런 다음 c.name으로 SORT를 하게 되는 거죠
 
 
Statistics
----------------------------------------------------------
         80  recursive calls
          0  db block gets
         57  consistent gets
          0  physical reads
          0  redo size
        651  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)
         13  rows processed
 
이번엔 EXISTS를 이용하는 예 입니다.
 
SQL> select c.name
  2  from s_customer c
  3  where exists (select 1 from s_ord o
  4                where o.customer_id = c.id);
 
NAME
--------------------------------------------------
Unisports
OJ Atheletics
Delhi Sports
Womansport
Kam's Sporting Goods
Sportique
Muench Sports
Beisbol Si!
Futbol Sonora
Kuhn's Sports
Hamada Sport
 
NAME
--------------------------------------------------
Big John's Sports Emporium
Ojibway Retail
 
13 개의 행이 선택되었습니다.
 
   : 00:00:00.03
 
Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   FILTER
   2    1     TABLE ACCESS (FULL) OF 'S_CUSTOMER'
   3    1     TABLE ACCESS (FULL) OF 'S_ORD'
 
이 경우엔 S_CUSTOMER를 전체 스캔하고 S_ORD도 전체 스캔하여 필터링(ID가 같은 데이터가 있는지) 하므로 SORT를 이용하지는 않습니다. 그러므로 앞의 쿼리와 추출되는 데이터의 개수는 같지만 순서는 달리 나오는 겁니다.
 
 
Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
         49  consistent gets
          0  physical reads
          0  redo size
        651  bytes sent via SQL*Net to client
        503  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
         13  rows processed
 
 
[실습]
select * from dba_free_spaces
select * from dba_rollback_segs
 
create table cust (
   cust_id varchar2(10),
   cust_name varchar2(50));
  
  
create table sale(
    cust_id varchar2(10),
    goods_id varchar2(10),
    sale_amt number);
   
insert into cust values ('1', '김길동');
insert into cust values ('2', '홍길동');
insert into cust values ('3', '나길동');
insert into sale values ('1', 'A001',1000);
insert into sale values ('1', 'B001',2000);
insert into sale values ('2', 'C001',4000);
insert into sale values ('2', 'D001',5000);
commit
SQL> select * from cust;
CUST_ID        CUST_NAME                                         
-------------- --------------------------------------------------
1              김길동                                           
2              홍길동                                           
3              나길동                                           
3 rows selected.
SQL> select * from sale;
CUST_ID        GOODS_ID         SALE_AMT        
-------------- ---------------- ----------------
1              A001                         1000
1              B001                         2000
2              C001                         4000
2              D001                         5000
4 rows selected.
 
-- 매출이 있는 고객데이터가 4건이다.
SQL> select c.cust_name 
  from cust c, sale s
 where c.cust_id = s.cust_id;
CUST_NAME                                         
--------------------------------------------------
김길동                                           
김길동                                           
홍길동                                           
홍길동                                           
4 rows selected.
 


-- 이름이 같으면 한건만 로딩
SQL> select distinct c.cust_name 
  from cust c, sale s
 where c.cust_id = s.cust_id;
CUST_NAME                                         
--------------------------------------------------
김길동                                           
홍길동                                           
2 rows selected.

-- exists로 구현
SQL> select c.cust_name
  from cust c
 where exists (select 1 from sale s
               where s.cust_id = c.cust_id);
CUST_NAME                                         
--------------------------------------------------
김길동                                           
홍길동                                           
2 rows selected.

댓글 없음:

댓글 쓰기