스프링 - Part 3 - 기본적인 웹 게시물 관리 06 (오라클 데이터베이스 페이징 처리)
오라클 데이터베이스 페이징 처리
구현된 기능들 중 가장 미숙한 부분은 목록 페이지이다. 목록 페이지는 기본적으로 페이징 처리가 필요한데 상식적으로 생각해 봐도 수 많은 데이터를 한페이지에서 보여주면, 처리성능에 영향을 미친다. 또한 브라우저에서도 역시 데이터의 양이나 처리속도에 문제를 일으키게 된다.
order by의 문제
데이터베이스를 이용할 때 웹이나 애플리케이션에 가장 신경 쓰는부분
- 빠르게 처리되는 것
- 필요한 양만큼만 데이터를 가져오는 것
빠르게 동작하는 SQL을 위해서는 먼저 order by를 이용하는 작업을 가능하면 하지말아야한다.
order by는 데이터가 많은 경우에 엄청난 성능의 저하를 가져오기 때문에
- 데이터가 적은 경우
- 정렬을 빠르게 할 수 있는 방법이 있는 경우가 아니라면 order by는 주의해야한다.
실행 계획과 order by
데이터 베이스에 전달된 SQL 문은 피싱 > 최적화 > 실행 과정을 거쳐서 처리된다.
예) '게시물 번호의 역순으로 출력' 을 처리 한다면 SQL Developer 에서 다음과 같이 처리할 수 있다.
상단의 버튼 중에는 SQL에 대해서 실행계획을 쉽게 볼수있도록 버튼을 제공한다.
F10 - 계획 설명
// SQL
-- 게시물 번호의 역순으로 출력
select * from tbl_board order by bno desc;
insert into tbl_board(bno, title, content, writer)
(select seq_board.nextval, title, content, writer from tbl_board);
select * from tbl_board order by bno +1 desc;
select * from tbl_board order by bno desc;
order by 보다는 인덱스
Select
/* + index_desc(tbl_board pk_board) */
*
from
tbl_board
where bno>0;
PK_BOARD라는 인덱스
tbl_board 테이블을 생성했을 때의 SQL을 다시한번 살펴보기
create table tbl_board (
bno number(10,0),
title varchar2(200) not null,
content varchar2(2000) not null,
writer varchar2(50) not null,
regdate date default sysdate,
updatedate date default sysdate
);
alter table tbl_board add constraint pk_board primary key(bno);
왼쪽은 인덱스, 오른쪽은 실제 테이블
왼쪽 그림을 보면 bno 값이 순서대로 정렬된 것을 볼 수 있다, 오른쪽은 테이블 모습이다. 테이블은 순서가 섞여있는 경우가 대부분이다.
인덱스와 실제 테이블을 연결하는 고리는 ROWID라는 존재이다. ROWID는 데이터베이스 내의 주소에 해당하는데 모든 데이터는 자신만의 주소를 가지고 있다.
실행 계획을 보면 이러한 생각이 데이터베이스 내에서 진행 되는 것을 확인 할 수 있다.. 안쪽을 먼저 보면 PK_BOARD 는 인덱스이므로 먼저 인덱스를 이용해서 100번 데이터가 어디에 있는지 ROWID를 찾아내고, 바깥쪽을 보면 BY INDEX ROWID 라고 되어 있는 말 그대로 ROWID를 통해서 테이블에 접근하게 된다.
인덱스를 이용하는 정렬
인덱스에서 가장 중요한 개념 중 하나는 정렬이 되어 있다는 점 이다. 정렬이 이미 되어 있는 상태이므로 데이터를 찾아내서 이들을 SORT 하는 과정을 생략 할 수 있다.
bno의 역순으로 정렬한 결과를 원한다면 이미 정렬된 인덱스를 이용해서 뒤에서부터 찾아 올라가는 방식을 이용할 수 있다. 이때 뒤에서부터 찾아 올라간다는 개념이 DESCENDING이다.
실행 계획을 살펴보면 PK_BOARD라는 인덱스를 이용하는데 DESCENDING을 하고 있는 것을 볼 수 있다.
인덱스와 오라클 힌트(hint)
select * from tbl_board order by bno desc;
select /*+INDEX_DESC (tbl_board pk_board)*/ * from tbl_board;
힌트 사용 문법
select문을 작성할 때 힌트는 잘못 작성되어도 실행할 때는 무시되기만 하고 별도의 에러는 발생하지 않는다.
우선 힌트를 사용할 때에는 다음과 같은 문법을 사용한다.
select /*+ Hint name(param...) */ column name, ...
from table name
....
힌트 구문은 /*+로 시작하고 */ 로 마무리된다. 힌트 자체는 SQL로 처리되지 않기 때문에 위의 그림처럼 뒤에 칼럼명이 나오더라도 별도의 ' , '로 처리되지 않는다.
FULL 힌트
INDEX_ASC, INDEX_DESC 힌트
INDEX_ASC/DESC 힌트는 테이블 이름과 인덱스 이름을 같이 파라미터로 사용한다.
/* 내림차순 정렬 */
order by 이용해서 bno 내림차순 정렬 조건 where bno > 0
/*+ */ 힌트를 이용해서 bno 내림 차순 정렬 조건 where bno > 0
select * from tbl_board where bno > 0 order by bno desc;
select /*+ INDEX_ASC(tbl_board pk_board) */ * from tbl_board where bno > 0;
select /*+ INDEX_ASC(tbl_board pk_board) */ * from tbl_board where bno > 0;
select * from tbl_board where bno > 0 order by bno desc;
ROWNUM과 인라인뷰
오라클 데이터베이스는 페이지 처리를 위해 ROWNUM이라는 특별한 키워드를 사용해서 데이터에 순번을 붙여 사용한다.
ROWNUM은 쉽게 생각해서 SQL이 실행된 결과에 넘버링을 해준다고 생각하면 된다.
ROWNUM은 실제 데이터가 아니라 테이블에서 데이터를 추출한 후에 처리되는 변수이므로 상황에 따라서 그 값이 매번 달라질 수 있다.
select rownum rn, bno, title from tbl_board;
select /*+ FULL(tbl_board) */ rownum rn, bno, title from tbl_board where bno>0 order by bno;
인덱스를 이용한 접근 시 ROWNUM
PK_BOARD 인덱스를 통해서 접근한다면 다음과 같은 과정으로 접근한다.
- PK_BOARD 인덱스를 통해서 테이블에 접근
- 접근한 데이터에 ROWNUM 부여
select /*+ index_asc(tbl_board pk_board */ rownum rn, bno, title, content from tbl_board;
FULL : 전체 데이터베이스 접근 방식 : 데이터가 저장되는 위치가 제 각각(rowid) 으로 출력 <- 시간이 많이 걸림
index : 자동 정렬 : 인덱스를 이용해서 원하는 데이터가 순서대로 출력 <- 시간이 절약
select /*+ index_desc(tbl_board pk_board */ rownum rn, bno, title, content from tbl_board;
페이지 번호 1, 2의 데이터
한 페이지당 10개의 데이터를 출력한다고 가정하면 ROWNUM 조건을 WHERE 구문에 추가해서 작성한다.
select /*+ index_desc(tbl_board pk_board */
rownum rn, bno, title, content
from tbl_board
where rownum <= 10;
-- 아무 결과가 나오지 않는다.
select /*+ index_desc(tbl_board pk_board */
rownum rn, bno, title, content
from tbl_board
where rownum > 10 and rownum <= 20;
SQL을 보면 rownum이 10보다 크고 20보다 작거나 같은 데이터들을 가져올 것이라고 기대하지만 실제로는 아무 결과가 나오지 않는다. 이렇게 되는 이유를 알아내려면 실행 계획을 잘 살펴봐야한다.
select /*+ INDEX_DESC(tbl_board pk_board */
rownum rn, bno, title, content
from tbl_board
where rownum <= 20;
인라인뷰(In-line View) 처리
데이터베이스에서 테이블이나 인덱스와 같이 뷰(View)라는 개념이 존재한다. 뷰(View)는 일종의 창문 같은 개념으로 복잡한 SELECT 처리를 하나의 뷰로 생성하고 사용자들은 뷰를 통해서 복잡하게 만들어진 결과를 마치 하나의 테이블처럼 쉽게 조회한다는 개념이다.
인라인뷰는 이러한 뷰의 작서을 별도로 작성하지 않고 말 그대로 FROM 구문 안에 바로 작성하는 형태이다.
외부에서 SELECT문은 인라인뷰로 작성된 결과를 마치 하나의 테이블처럼 사용한다.
select bno, title, content
from
(
select /*+ INDEX_DESC(tbl_board pk_board */
rownum rn, bno, title, content
from tbl_board
where rownum <= 20
)
where rn > 10;
20을 30으로 하면 그다음 페이지 출력
(where rownum <= 30)