메뉴 건너뛰기

bysql.net

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

웹게시판에서 부분범위처리는 한번 읽은 페이지의 시작점과 마지막점의 정보를 가지고 있다, 다음 페이지를 요구할때 현제 페이지의 마지막 점부터 액세스하는 형태로 처리한다.

1. 인덱스를 활용한 정렬을 통해 전체범위 처리를 하지 않고 추출할 대상에 바로 접근

2. ROWNUM을 이용하여 원하는 만큼만 절단해 오는 것

3. 연쇄(Concatenation) 실행계획을 활용하는 것

SELECT * FROM sales WHERE sal_dept >= '1234' AND seq >= 111;

는 시작점이 고정( = )되어 있지 않아, 내부적으로 전체범위 처리로 수행된다. 이를 연쇄 실행계획을 활용하여 처리가 될수 있도록 연산을

두개로 나누어서 처리하도록 한다.

SELECT * FROM sales W

HERE (sal_dept > '1234')                         ------------ (2)

OR (sal_dept = '1234' AND seq >= 111); ------------(1)

(1)의 범위가 먼저 부분범위 처리로 수행되고, (2)의 범위가 다시 부분범위 처리로 수행된다.

 

가) 웹 게시판 부분범위처리 사례 1 ( NON-UNIQUE INDEX ) - 가장 단순한 경우

고객명(cust_name)은 인덱스로 cust_name_idx 으로 가정한다.

[ - 처음 실행 시 - ]

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(y cust_name_idx) */ ROWIDTOCHAR(rowid) rid, cust_name, ...

FROM cust_table y

WHERE :v2 = 'PREV' AND (cust_name <: v3 OR (cust_name = :v3 AND rowid < CHARTOROWID(:v4)))

AND rownum <= 25

ORDER BY cust_name, rid;

- v2 = FIRST : cust_name인덱스로만 처리되어 rownum으로 25개를 액세스

- v2 = NEXT : FIRST에서 마지막에 액세스한 cust_name, rowid 으로 액세스

- v2 = PREV : FIRST에서 첫번재 액세스한 cust_name, rowid 으로 액세스

 

나) 웹 게시판 부분범위처리 사례 2 ( UNIQUE INDEX) - 기본키의 순서에 따라 출력

게시판ID(bbs_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) */ (26-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;

- sw = NEXT( 처음, 다음 ) : 처음 init_dt는 입력받은 날자나 sysdate 값으로, v_num은 최대한 (ex: 9999999)으로 지정

          다음 페이지 경우, 앞 페이지의 마지막 로우 값으로 지정해야 한다.

- sw = PREV ( 이전 ) : 처음 페이지의 첫 번재 로우 값으로 지정

 

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

나) 사례에서 처음, 끝 부분만 추가 되었으므로 패스

 

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

게시판에서 '다음페이지', '이전페이지' 이동을 표시하는 개념이다.

SELECT rnum, bbs_id, cre_dt, num

FROM (

SELECT /*+ USE_CONCAT INDEX_DESC(a bbs_idx1) */ ROWNUM rnum, bbsid, 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 = :v_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;

이 SQL에서 얻고자 하는 것은 각 페이지의 첫 번째 로우의 정보들이다!!!!

여기에서 얻은 정보로 각 페이지의 리스트를 구한다.

SELECT /*+ USE_CONCAT INDEX_DESC(a bbs_idx1) */ bbs_id, cre_dt, num, c_text

FROM billboard a WHERE bbs_id = :bbs AND (cre_dt < :v_init_dt OR (cre_dt = :v_init_dt AND num <= :v_num) ) AND rownum <= 20;

 

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

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

- 마지막 글이 원본글로부터 몇 번째 순번의 글인가?

2) 계층구조의 전개를 어떻게 부분범위 처리로 할 것인가냐에 대한 방법

- 계층구조를 전개할 때 정말 우리가 원하는 만큼만 전개하다가 멈추도록 할 수 있느냐?

SELECT id, pid, c_text, substr(path, 3, 3) * 1 parent_id

FROM (

SELECT ROWNUM rnum, id, pid, writer, LPAD(' ', 2*LEVEL-1)||c_text c_text, SYS_CONNECT_BY_PATH( TO_CHAR(id, '999'), '/') path

FROM billboard

CONNECT BY pid = PRIOR id AND rownum <= 10 + :cnt

START WITH parent_sw = 1 AND id >= :start_id

)

WHERE rnum BETWEEN :cnt AND 10+:cnt AND rownum < 10;

인덱스 : pid + id, parent_sw + 1

글번호 = id, 상위글번호 = pid, 내용 = c_text, 답글 = parent_sw = 0, 원본글 = parent_sw = 1

:cnt = 어떤 페이지를 처리할 때 해당 페이지의 시작 건이 자신의 원본글에서 몇 번째의 순번인가를 지정

:start_id = 페이지의 시작 건의 원본글 번호

 

==> 뒷 부분 이해가 아직 부족하여 잠시 skip 하겠습니다...