1.4.9. 웹 게시판에서의 부분범위처리

웹형태의 에플리케이션에서는 페이지 단위로 처리가 종료되는 형식을 취하게 된다.
따라서 한 페이지에 표시할 만큼만 액세스할 수 있다면 그것이 최선이 될 것이다.

웹게시판의 부분범위처리를 위한 기본원리

  • 인덱스를 활용한 정렬을 통해 전체범위를 하지 않고 추출할 대상에 바로 액세스하는 것
  • rownum을 이용하여 원하는 만큼만 잘라오는 것
  • 연쇄(concatenation)실행계획을 활용하는 것

웹게시판 부분범위처리 사례1(NON-UNIQUE INDEX)

고객명(cust_name) non unique index일때


select /*+ index(w cust_name_idx */ 
       rowidtochar(rowid) rid, cust_name, ...
  from cust_table w
 where :v2 = 'FIRST' and cust_name like :v1 || '%'
   and rownum <= 25
union all
select /*+ use_concat index(x cust_name_idx */ 
       rowidtochar(rowid) rid, cust_name, ...
  from cust_table x
 where :v2 = 'NEXT' 
   and (cust_name > :v3 or
       (cust_name = :v3 and rowid > chartorowid(:v4) ) )
   and cust_name like :v1 || '%'
   and rownum <= 25
union all
select /*+ use_concat index_desc(x cust_name_idx */ 
       rowidtochar(rowid) rid, cust_name, ...
  from cust_table x
 where :v2 = 'PREV' 
   and (cust_name < :v3 or
       (cust_name = :v3 and rowid < chartorowid(:v4) ) )
   and cust_name like :v1 || '%'
   and rownum <= 25
 order by cust_name, rid

웹게시판 부분범위처리 사례2(UNIQUE INDEX)

기본키(billboard_uk)는 '게시판id+작성일자+글번호'로 구성되어 있을 경우


select bbs_id, 작성일자, 글번호, rnum
  from (select /*+ use_concat  index_desc(a billboard_uk) */
               rownum rnum, bbs_id, 작성일자, 글번호, 글내용
            from billboard a
         where :sw = 'NEXT'
           and bbs_id = :bid
           and (작성일자 < :init_dt or 
               (작성일자 = :init_dt and 글번호 < :v_num) )
           and rownum <= 25
         union all
        select /*+ use_concat  index_asc(a billboard_uk) */
               rownum rnum, bbs_id, 작성일자, 글번호, 글내용
           from billboard a
        where :sw = 'PREV'
          and bbs_id = :bid
          and (작성일자 > :init_dt or 
              (작성일자 = :init_dt and 글번호 > :v_num) )
          and rownum <= 25
       )
 order by rnum;

웹게시판 부분범위처리 사례3(처음,이전,다음,끝)


SELECT CDAY, CUST_NM, CID, CSEQ, CTEXT
  FROM (SELECT /*+ INDEX_ASC(a IDX01) */
               CDAY, CUST_NM, CID, CSEQ, CTEXT
          FROM CSTAB a
         WHERE :SW = 'FIRST'
           AND CDAY BETWEEN :B11 AND :B12
           AND ROWNUM <=25
         UNION ALL
        SELECT /*+ INDEX_DESC(a IDX01) */
               CDAY, CUST_NM, CID, CSEQ, CTEXT
          FROM CSTAB a
         WHERE :SW = 'LAST'
           AND CDAY BETWEEN :B11 AND :B12
           AND ROWNUM <=25
         UNION ALL
        SELECT /*+ USE_CONCAT INDEX_ASC(a IDX01) */
               CDAY, CUST_NM, CID, CSEQ, CTEXT
          FROM CSTAB a
         WHERE :SW = 'NEXT'
           AND ((CDAY > :B100) OR (CDAY = :B100 AND CID > :B20
            OR (CDAY = :B100 AND CID = :B20 AND CSEQ > :B27) )
           AND CDAY BETWEEN :B11 AND :B12
           AND ROWNUM <=25
         UNION ALL
        SELECT /*+ USE_CONCAT INDEX_DESC(a IDX01) */
               CDAY, CUST_NM, CID, CSEQ, CTEXT
          FROM CSTAB a
         WHERE :SW = 'PREV'
           AND ( (CDAY < :B100) OR (CDAY = :B100 AND CID < :B20
            OR (CDAY = :B100 AND CID = :B20 AND CSEQ < :B27) )
           AND CDAY BETWEEN :B11 AND :B12
           AND ROWNUM <=25 )
   ORDER BY CDAY, CID, CSEQ

웹게시판 부분범위처리 사례4(SET단위처리)


SELECT RNUM, BBS_ID, CRE_DT, NUM
  FROM (SELECT /*+ USE_CONCAT INDEX_DESC(a bbs_idx1) */
               ROWNUM RNUM, BBS_ID, CRE_DT, NUM
          FROM BILLBOARD a
         WHERE :SW = 'NEXT' AND BBS_ID = :V_BBS
           AND ( CRE_DT < :V_INIT_DT
            OR ( CRE_DT = :INIT_DT AND NUM <= :V_NUM) )
           AND ROWNUM <= 201
         UNION ALL
        SELECT /*+ USE_CONCAT INDEX_ASC(a bbs_idx1) */
               ((20*10)+2 - ROWNUM) RNUM, BBS_ID, CRE_DT, NUM
          FROM BILLBOARD a
         WHERE :SW = 'PREV' AND BBS_ID = :V_BBS
           AND ( CRE_DT > :V_INIT_DT
            OR ( CRE_DT = :INIT_DT AND NUM >= :V_NUM) )
           AND ROWNUM <= 201 
       )
 WHERE RNUM IN (1,21,41,61,81,101,121,141,161,181,201)
 ORDER BY RNUM

웹게시판 부분범위처리 사례5(계층구조의 처리)

페이지가 어느 단계에서 잘렸든 최상의 원본글 정보를 가지고 있어야 한다.

1. 처음 페이지를 처리하는 방법
원본글 들만 이용해 원하는 순서로 계층구조를 전개해 가다가 페이지가 채워지면 처리를 멈춘다.
이전/다음 처리를 위해서 최상위 레벨의 식별자 정보를 보유한다.
2. 다음 페이지를 처리하는 방법
마지막 글이 원본글로 부터 몇번째 순번의 글인지 알아야 한다.
해당 순번의 다음번 부터 잘라온다.
=> 추출 대상 로우는 한테이지에 나타나는 데이터의 수보다 많아진다.
3. 이전페이지를 처리하는 방법
=> SQL을 분리하여 절차형 처리를 가미해야한다.


SELECT ID, PID, C_TEXT,SUBSTR(PATH,3,3) * 1 PARENT_ID -------(e)
FROM (SELECT ROWNUM RNUM, ID, PID, WRITER,
             LPAD(' ', 2*LEVEL-1)||C_TEXT C_TEXT,
             SYS_CONNECT_BY_PATH(TO_CHAR(ID,'999'),'/') PATH -------(d)
        FROM BILLBOARD
     CONNECT BY PID = PRIOR IS
            AND ROWNUM <=10 + :CNT -------(b)
       START WITH PARENT_SW = 1 -------(a)
              AND ID >= :START_ID
     )
 WHERE RNUM BETWEEN :CNT AND 10+ :CNT -------(c)

문서에 대하여

  • 이 문서는 오라클클럽 대용량 데이터베이스 스터디 모임에서 작성하였습니다.
  • {*}이 문서의 내용은 이화식님의 새로쓴 대용량 데이터베이스 솔루션을 참고했습니다.*
  • 이 문서를 다른 블로그나 홈페이지에 게재할 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^\^