(Oracle+JSP) Oracle 10g Express Edition 에서 rownum 을 사용하여 레코드 잘라오기 MSSQL_MDB_Oracle

지금 테스트 중인 데이타베이스가 Oracle 10g Express Edition 이다.
Express 버전은 오라클 사이트에서 회원가입만 하면 무료로 다운로드 받아 사용할 수 있다.
이 버전은 특별히 사용상의 제약은 없지만, CPU 를 한개만 사용한다는 등의 성능상의 제약이 있다.
하지만, 소규모 사이트를 제작하는데에는 별 문제가 없어 보인다.

그래서일까?
rownum 을 사용하는데 제대로 동작하지 않았다.
rownum 이라는 것은, My SQL 의 Limit 나 MS-SQL 의 Top 과 같이 레코드를 몇개만 잘라서 가져올때 사용하는 방법이다.
즉, 오라클 쿼리에서만 사용된다.
rownum 은 실제로 존재하는 컬럼이 아니라, 데이타를 불러온후 가상으로 매겨지는 순번이다.
일종의 인덱스와 비슷한 기능으로, 레코드를 제어하기 편하도록 만들어진 기능인것 같다.

보편적으로 알려진 사용법은 아래와 같다.
member 라는 테이블이 있다고 가정했을때,

(용법1)
select * from member where rownum<11
설명을 하자면, 불러온 데이타를 일괄적으로 정렬해서 가상으로 매겨진 컬럼의 일련번호가 11 보다 작은 레코드를 가져온다.
이 쿼리는 아무 문제없이 잘된다.
그런데, 다음 쿼리에서는 아무 레코드도 가져오지 못하는 이상한 오류가 발생한다.

(용법2)
select * from member where rownum>2 and rownum<11
(용법3)
select * from member where rownum between 2 and 11

용법 2 와 3은 rownum 번호가 2 보다 크고 11 보다 작은 레코드를 가져오라는 구문이다.
그런데, 오라클 10g Express 버전에서만 그런것인지 아니면 다른 문제인지는 모르겠지만, 이렇게 쿼리를 보내면 아무 레코드도 가져오지 못했다.

11 이하로 잘라서 가져오는데에는 문제가 없는데, 범위를 정하면 못 불러온다?
이것은 아주 중요한 문제다.
레코드의 범위를 지정하여 잘라오는 것은 성능에 큰 영향을 미치기 때문이다.

통상, JSP 에서는 JDBC 엔진을 통해 레코드를 가져오는데,
통상적인 문법에서는 데이타를 범위지정 없이 가져온다.

예를 들어,

ResultSet rs = stmt.executeQuery(sql.toString());
while (rs.next()){
  컬럼정보 가져오기
}

라고 구문을 쓴다면, 이 구문에는 sql 쿼리에서 지정한 모든 레코드를 가져온다.
물론, 개발자가 해당 레코드에 별도의 인덱스 번호를 주고 잘라오도록 쿼리를 구성했다면 문제가 없다.
별도의 인덱스가 없고, rownum 에 의지해서 레코드를 잘라와야 한다면, 위의 구문에서는 잘라와 지지 않는 것이다.
결국, 데이타 양이 많아져서 몇만건을 넘어가기 시작하면, 점점 데이타를 불러오는 속도가 느려지게 되고, 나중에는 몇초에서 몇십초씩 기다려야 웹페이지가 열리는 문제가 발생하게 된다.
페이징(페이지를 블럭단위로 보여주기, 혹은 잘라서 가져오기) 을 위해서도 rownum 의 구간을 지정해서 불러오는 것은 중요한 문제다.

그래서, 자료를 이것저것 찾아봤는데, 해법을 제시한 누군가가 있었다.
링크: Criteria 사용하여 질의 하기 #2

위의 글에서 보면, 이중 쿼리를 이용해 nownum 을 한번 뒤집은 후 가져오는 것이다.
즉, rownum 용법이 구간을 지정하지 못하고 최고 한도만 지정할 수 있기 때문에,
일단 최고 한도를 지정하는 쿼리를 다시 뒤집어서 정렬한 후 한도를 지정해서 구간을 지정하는 효과를 내도록 구현한 것이다.
코드를 약간 수정하였다.

-------------------------------------------------
Oracle 10g Express Edition
-------------------------------------------------
    select
        * 
    from
        ( select
            row_.*,
            rownum rownum_ 
        from
            ( select
                * 
            from
                테이블명 ) row_ 
        where
            rownum <= ?
        ) 
    where
        rownum_ > ? 
-------------------------------------------------
위와 같이 구현된 기본 용례를 아래와 같이 적용한다.
member 라는 테이블이 있다고 가정했을때,

select * from (select A.*, rownum rownum_ from (select * from member) A where rownum<=6) where rownum_>3

위와같이 쿼리를 처리하면, 마치 rownum 의 구간을 지정해서 처리한것과 똑같은 효과가 생긴다.
범위는 rownum 이 3 보다 크고 6 보다 작거나 같은 범위를 지정한 것이다.
쿼리에서 보여지는 'rownum_' 과 'A' 등은 쿼리를 처리하기 위해 일시적으로 지정한 것이므로 신경쓰지 않아도 된다.
JSP 에서 사용할때는 구간값으로 쓰인 '3' 과 '6' 부분을 변수로 처리하면 된다.

물론, 이렇게 해서 성능향상이 보장되지는 않는다.
쿼리 자체에 'select * from member' 가 들어가 있기 때문이다.
위에서 언급한것처럼, 최초 테이블 설계시 rownum 에 의존하지 않고 별도의 인덱스를 만들어서 처리하는 것이 성능향상에 도움이 될 것으로 보여진다.
여기서 언급하고자 하는 것은, 중소규모의 사이트에서 테이블에 인덱스를 만들지 않았거나 혹은 인덱스를 만들 상황이 안될때의 임시적인 처리라 할 수 있다.


덧글

댓글 입력 영역
* 비로그인 덧글의 IP 전체보기를 설정한 이글루입니다.


통계 위젯 (화이트)

1281531
9847
10318458

google_myblogSearch_side

▷검색어

Flag Counter style2