본문 바로가기

ORACLE

부분범위 처리

emp란 테이블에 2천만건의 데이터가 있다고 할때


select * from emp와  select * from emp where name like '장%'


이 두개의 결과는 전자가 더 빠르게 나올 수 있다.

(물론 인덱스가 없다고 가정..)


왜냐하면 풀스캔을 할 경우 그냥 차례대로 읽어내려가면 되기 때문에 오라클이 가지고 있는


버퍼 사이즈에 도달하게 되면 비록 2천만건을 다 읽지 않았더라도 화면으로 내보내기 때문이다.


반면 like '장%'라는 조건이 들어가면 버퍼 사이즈에 읽어들인 데이터가 다 찰때까지 테이블을


스캔해 내려가야 하기 때문에 속도가 훨씬 늦어지는 것이다. 인덱스가 있다면 얘기가 달라지겠지만....



전체범위 처리의 예를 몇가지 더 보면


select date from order order by date DESC ..나


max()사용한 쿼리등이 전체범위를 일으키는 주범들이다..특히 order by 같은 경우 소트를 위해서


해당 조건에 들어가는 모든 데이터를 다 읽고나서 소트 후 보여주기 떄문이다.


이것은 인덱스를 사용하면 해소가 가능하다..(인덱스 자체가 밸런스 트리 구조로 소트가 되어있기


때문에..)


date로 만든 인덱스가 있다고 가정하면


select /*+ index_desc(order_date) */ date from where date < '99991231'


인덱스를 위 방식처럼 역으로 태우면 자연히 date순으로 소트가 되어 나오며..


max()를 대신한다면..


select /*+ index_desc(order_date) */ date from where date < '99991231'

and rownum = 1


로 하면 가장 큰 값을 얻어낼 수 있다.



또 하나가 count이다..


select count(name) into :A from ...


if A>0 ....


이런식으로 되어있는 로직이 있다고 할때 굳이 0보다 크다고 비교할 것을 count를 사용해서

모든 데이터를 읽어들일 필요가 없다는 것이다.


이런 경우는


select 1 into :A from dual where exists(select 'X' from ....where..)


if A > 0

한건이라도 있다면 이미 조건에 만족하기 때문에 굳이 count를 사용할 이유가 없는 것이다.


근데 exists가 죽어도 싫다...


라고 하면..


rownum=1 이라도 붙여주자 -_-;;;;



마지막으로 1:M 조인의 부분범위 처리를 보면

예를들어  아래와 같은 쿼리가 있다고 보자.


select x.cust_no , x.addr, x.name, ...

from cust x, req y

where x.cust_no = y.cust_no

and x.cust_stat in ('A','C','F')

and y.un_pay > 0

group by x.cust_no

having sum(y.un_pay) between :val1 and :val2


위의 쿼리는.. 고객 테이블과 청구테이블을 조인하여

고객번호로 그룹을 만들어 미수금의 합계가 val1 과 val2 사이의

사용자만을 보고 싶다는 것이다.


쿼리를 자세히 보면 우리가 보고 싶은 값은 전부 cust 테이블에 있다.이럴땐

from절에 cust만 나오는게 맞다.


이럴 경우에는 조인을 사용하는 것이 아니다..

아래와 같이 수정하자.


select x.cust_no,x.addr,x.name...

from cust x

where cust_stat in ('A',...)

and exists(select 'X' from req y where y.cust_no = x.cust_no

                and un_pay > 0 (미수금이 있을때)

                group by x.cust_no

                having sum(y.un_pay) between :val1 and :val2)

이것의 단점은.. y측의 미수금합계 즉 sum(y.un_pay)를 같이 보여 줄 수 없다는 것이다.

서브쿼리의 내용을 메인쿼리에서 사용 할 수가 없기 떄문이다.(반대는 가능)


위처럼 미수금합계를 같이 보고 싶다라고 할때 함수를 사용하는 것이다..