본문 바로가기

Programming/Oracle

[펌] ORACLE rownum 설명.. 그리고 hint 절을 사용하자.. 게시판 페이지처리

출처 : http://superflux.tistory.com/3731


오라클에서 rownum 은 쿼리가 실행될 때 결과 레코드에 번호를 나타내어 주는 필드이다.
물론 table을 만들 때 rownum을 만들어줄 필요는 없다.

어떠한 테이블이라도
"select rownum from boardtable" 의 형태로 쿼리를 날리면 레코드에 번호가 나타내어 주는 것을 볼 수 있을 것이다...

따라서 페이징을 위한 쿼리에서 우리는 rownum이 10 보다 크고 20보다 작은...
이런 식의 조건을 주어.. 원하는 범위의 레코드만 쿼리 할 수 있다..

select * from boardtable where rownum > 10 and rownum <= 20

그래서 위와 같이 쿼라하면 어떨까?
결과가 하나도 않나올 것이다.. 왜냐하면.. 쿼리가 실행되면 where 절 부분이 먼저 실행 될 것이고.. select 를 하기전에는 rownum이 없기 때문이다.
따라서, rownum을 긁어오는 쿼리를 한번 미리 해줄 필요가 잇다..

select * from (select rownum numrow , boardtable.* from boardtable) where numrow > 10 and numrow <= 20

order by 절을 사용하지 않는다면 이것만으로 우리는 행복할 수 있다.

select * from (select rownum numrow , boardtable.* from boardtable order by reg_date desc) where numrow > 10 and numrow <= 20

결과는 원하는 대로 되지 않음을 볼 수 있다.
이유는 아마도.... order by 가 rownum 값을 만드는데 영향을 못주는 것이라고 생각되는데.. 즉.. order by를 지정한다고 해도.. rownum은 최초의 order by 가 없는 상태로 만들어진다고 추측할 수 있다..
select rownum numrow , boardtable.* from boardtable order by reg_date desc
select rownum numrow , boardtable.* from boardtable
위의 두 쿼리는 실제로 rownum 값을 똑같이 만들어준다.. 물론 뿌리는 순서는 다르지만..

따라서 원하는대로 정렬을 할려면..

select rownum numrow , aa.* from ( select * from boardtable order by reg_date desc ) aa

위의 형태로 쿼리를 바꾸어 줘야 한다.
그런데 또 우리는 범위를 지정해야 하니까..

select rownum numrow , aa.* from ( select * from boardtable order by reg_date desc ) aa where numrow > 10 and numrow <= 20

하면 아무것도 안나오는 이유는 이미 설명했고..

select rownum numrow , aa.* from ( select * from boardtable order by reg_date desc ) aa where numrow > 10 and numrow <= 20

따라서...

select * from ( select rownum numrow , aa.* from ( select * from boardtable order by reg_date desc ) aa ) where numrow > 10 and numrow <= 20

위와 같이 해주면 되겟다..
그런데 좀 복잡하다.. 더구나 검색을 한번... 두번... 세번 을 하니...
데이타 양이 많다면 쿼리실행속도가 느려질 가능성이 있다..
물론 속도에 가장 큰 영향을 주는 것은 order by 이지만 ...
그래서 index를 만들고 hint 절을 써야할 이유가 생기는 것이다..
인덱스는 order by 를 하는 필드에 주면 된다..
따라서.. reg_date 필드에 인덱스를 주면 되고...
그러나 hint 절을 사용하려면 유니크 속성이 있어야 한다..
따라서.. 인덱스를 줄 때 reg_date 필드와 프라이머리 키 필드를 같이 걸어주면 유닉속성을 이용할 수 있다..

create unique index idx_board_reg_date on boardtable (reg_date, idx)

인덱스가 생성된다..

select /*+ index_desc(boardtable idx_board_reg_date) */ rownum, tvulist.* from tvulist

order by 없이 rownum이 제대로 긁어지나?

select * from (select /*+ index_desc(tvulist idx_board_reg_date) */ rownum as numrow, boardtable.* from boardtable ) where numrow > 10 and numrow <= 20

이제 위와 같이하면...
원하는 범위의 데이타를 가져올 수 있겠다..

만일 인덱스를 사용하지 않앗는데... 데이타가 튀어나오는 시간이 좀 늦는다 싶으면..
인덱스를 사용하라.. 행복할 것이다..