For Programmer

PART3 - 스프링 MVC 프로젝트의 기본 구성(5): 오라클 데이터 베이스에서 페이징 처리 본문

Spring/스프링 프로젝트

PART3 - 스프링 MVC 프로젝트의 기본 구성(5): 오라클 데이터 베이스에서 페이징 처리

유지광이 2020. 9. 8. 18:23
728x90

오라클 데이터베이스 페이징 처리 

-구현된 기능들 중 가장 미숙한 부분은 목록 페이지입니다. 목록 페이지는 기본적으로 페이징 처리가 필요한데 상식적으로 생각해 봐도 수많은 데이터를 한 페이지에서 보여주면, 처리 성능에 영향을 미칩니다. 또한 브라우저에서도 역시 데이터의 양이나 처리속도에서 문제를 일으키게 됩니다. 일반적으로 페이징 처리는 크게 번호를 이용하거나 '계속 보기'등의 형태로 구현됩니다. 번호를 이용한 페이징 처리는 과거 웹 초기부터 이어오던 방식이고,'계속 보기'는 Ajax와 앱이 등장한 이후에 '무한 스크롤'이나 '더 보기'와 같은 형태로 구현됩니다. 예제에서 목록 페이지는 전통적인 번호를 이용하는 방식으로 처리하게 됩니다. 참고로 오라클은 MySQL에 비해서 추가적인 지식이 필요합니다.

 

-order by의 문제

프로그램을 이용해서 정렬을 해본 적이 있다면 데이터의 양이 많을수록 정렬이라는 작업이 얼마나 많은 리소스를 소모하는지 알 수 있습니다. 데이터베이스는 경우에 따라서 수백만 혹은 천만개 이상의 데이터를 처리하기 때문에 이 경우 정렬을 하게 되면 엄청나게 많은 시간과 리소스를 소모하게 됩니다. 데이터베이스를 이용할 때 웹이나 애플리케이션에 가장 신경 쓰는 부분은 1)빠르게 처리 되는 것, 2)필요한 양만큼만 데이터를 가져오는 것입니다. 예를 들어, 거의 모든 웹페이지에서 페이징을 하는 이유는 최소한의 필요한 데이터만을 가져와서 빠르게 화면에 보여주기 위함입니다. 빠르게 동작하는 SQL을 위해서는 먼저 order by를 이용하는 작업을 가능하면 하지 말아야 합니다. order by는 데이터가 많은 경우에 엄청난 성능의 저하를 가져오기 때문에 1) 데이터가 적은 경우와 2)정렬을 빠르게 할 수 있는 방법이 있는 경우가 아니라면 order by는 주의해야만 합니다.

 

-실행 계획과 order by

오라클의 페이징 처리를 제대로 이해하기 위해서 반드시 알아두어야 하는 것이 실행 계획입니다. 실행 계획은 말 그대로 SQL을 데이터베이스에서 어떻게 처리할 것인가? 에 대한 것입니다. SQL이 데이터베이스에 전달되면 데이터베이스는 여러 단계를 거쳐서 해당 SQL을 어떤 순서와 방식으로 처리할 것인지 계획을 세우게 됩니다. 데이터베이스에 전달된 SQL문은 아래와 같은 과정을 거쳐서 처리됩니다.

SQL 파싱 -> SQL 최적화 -> SQL 실행1)SQL 파싱 단계에서는 SQL 구문에 오류가 있는지 SQL을 실행해야 하는 대상 객체(테이블,제약 조건,권한 등)가 존재하는지를 검사합니다. 2)SQL 최적화 단계에서는 SQL이 실행되는데 필요하는 비용(cost)을 계산하게 됩니다. 이 계산된 값을 기초로 해서 어떤 방식으로 실행하는 것이 가장 좋다는 것을 판단하는 '실행 계획'을 세우게 됩니다.SQL 실행 단계에서는 세워진 실행 계획을 통해서 메모리 상에서 데이터를 읽거나 물리적인 공간에서 데이터를 로딩하는 작업 등을 하게 됩니다.개발자들은 도구를 이용하거나 SQL Plus 등을 이용해서 특정한 SQL에 대한 실행 계획을 알아볼 수 있습니다. SQL Developer에서는 간단히 버튼을 클릭해서 실행계획을 확인할 수 있습니다. 예를 들어 '게시물 번호의 역순으로 출력하라'는 처리를 한다면 SQL Developer에서 다음과 같이 처리할 수 있습니다.

상단의 버튼 중에는 SQL에 대해서 '실행 계획'을 쉽게 볼 수 있도록 버튼이 제공됩니다.

빨간색 줄 처진곳(단축기:F10)

실행 계획을 보면 트리 구조로 방금 전 실행한 SQL이 어떻게 처리된 것인지를 알려줍니다. 흔히 SQL 튜닝이라고 하는 작업은 이를 보고 어떤 방식이 더 효과적인지를 판단해서 수정하게 됩니다.

*가장 간단하게 실행 계획을 보는 방법은 '안쪾에서 바깥쪽으로, 위에서 아래로' 봐주면 됩니다. 위 그림의 내용을 해석하자면 'TBL_BOARD' 테이블을 'FULL'로 접근하고 내림차순으로 정렬했다는 것을 의미합니다. 'FULL'이라는 의미는 테이블 내의 모든 데이터를 스캔했다는 의미입니다. PK_BOARD라는 것을 이용해서 접근하고 기존과 달리 맨 위의 SORT 과정이 없는 것을 볼 수 있습니다. 이것을 이해하려면 index라는 개념을 알 필요가 있습니다. index에 대한 설명은 밑에서 하겠습니다. 결국은 실행 계획을 세우는 것은 데이터베이스 내에서 하는 역할이기 때문에 데이터의 양이나 제약 조건등의 여러 상황에 따라서 데이터베이스는 실행 계획을 다르게 작성합니다.

 

-order by 보다는 인덱스(index)

데이터가 많은 상태에서 정렬 작업이 문제가 된다는 사실을 알았다면, 이 문제를 어떻게 해결해야 하는지를 살펴보겠습니다. 가장 일반적인 해결책은 '인덱스(index)를 이용해서 정렬을 생략하는 방법' 입니다. 결론부터 말하자면 '인덱스'라는 존재가 이미 정렬된 구조이므로 이를 이용해서 별도의 정렬을 하지 않는 방법입니다. 

위의 사진에서 보면 1)SORT를 하지 않았다는 점, 2)TBL_BOARD를 바로 접근하는 것이 아니라 PK_BOARD를 이용해서 접근한 점, 3)RANGE SCAN DESCENDING, BY INDEX ROWID로 접근했다는 점입니다.

 

-PK_BOARD라는 인덱스

tbl_board 테이블을 생성했을 때의 SQL을 다시 한 번 살펴 보겠습니다.

CREATE TABLE TBL_BOARD 
(
  BNO NUMBER(10, 0) NOT NULL 
, TITLE VARCHAR2(200 BYTE) NOT NULL 
, CONTENT VARCHAR2(2000 BYTE) NOT NULL 
, WRITER VARCHAR2(50 BYTE) NOT NULL 
, REGDATE DATE DEFAULT sysdate 
, UPDATEDATE DATE DEFAULT sysdate );

alter table tbl_board add constraint pk_board primary key(bno);

*테이블을 생성할 때 제약 조건으로 PK를 지정하고 PK의 이름이 'pk_board'라고 지정하였습니다. 데이터 베이스에서 PK는 상당히 중요한 의미를 가지는데, 흔히 말하는 '식별자' 의미와 '인덱스'의 의미를 가집니다. '인덱스'는 말 그대로 '색인'입니다. 우리가 가장 흔히 접하는 인덱스는 도서 뒤쪽에 정리되어 있는 색인입니다. 색인을 이용하면 사용자들은 책 전체를 살펴볼 필요 없이 색인을 통해서 자신이 원하는 내용이 책의 어디에 있는지 알 수 있습니다. 데이터베이스에서 인덱스를 이해하는 가장 쉬운 방법은 데이터베이스의 테이블을 하나의 책이라고 생각하고 어떻게 데이터를 찾거나 정렬하는지를 생각하는 것입니다. 색인은 사람들이 쉽게 찾아볼 수있게 알파벳 순서나 한글 순서로 정렬합니다. 이를 통해서 원하는 내용을 위에서부터 혹은 반대로 찾아나가는데 이를 '스캔(scan)'한다고 표현합니다. 데이터베이스에 테이블을 만들 때 PK를 부여하면 지금까지 얘기한 '인덱스'라는 것이 만들어집니다. 데이터베이스를 만들 때 PK를 지정하는 이유는 '식별'이라는 의미가 있지만, 구조상으로는 '인덱스'라는 존재(객체)가 만들어지는 것을 의미합니다. tbl_board테이블은 bno라는 칼럼을 기준으로 인덱스를 생성하게 됩니다. 인덱스와 실제 테이블을 연결하는 고리는 ROWID라는 존재입니다. ROWID는 데이터베이스 내의 주소에 해당하는데 모든 데이터는 자신만의 주소를 가지고 있습니다. SQL을 통해서 bno값이 68번인 데이터를 찾고자 할때 이를 처리하는 데이터베이스 입장에서는 tbl_board라는 책에서 bno 값이 68인 데이터를 찾아야합니다. 만일 책이 얇아서 내용이 많지 않다면 속히 전체를 살펴보는 것이 더 빠를 것입니다.(이를 데이터베이스 쪽에서는 'FULL SCAN'이라고 표현합니다.) 하지만 내용이 많고,색인이 존재한다면 당연히 색인을 찾고 색인에서 주소를 찾아서 접근하는 방식을 이용할 것입니다. 아래의 사진에서 실행계획을 보면 이러한 생각이 데이터베이스 내에서 진행되는 것을 확인할 수 있습니다. 안쪽을 먼저 보면 PK_BOARD는 인덱스이므로 먼저 인덱스를 이용해서 68번 데이터가 어디에 있는지 ROWID를 찾아내고, 바깥쪽을 보면 'BY INDEX ROWID'라고 되어있는 말 그대로 ROWID를 통해서 테이블에 접근하게 됩니다.

 

-인덱스를 이용하는 정렬

인덱스에서 가장 중요한 개념 중 하나는 '정렬이 되어 있다는 점'입니다. 정렬이 이미 되어있는 상태 이므로 데이터를 찾아내서 이들을 SORT 하는 과정을 생략할 수 있습니다.'bno의 역순으로 정렬한 결과'를 원한다면 이미 정렬된 인덱스를 이용해서 뒤에서부터 찾아 올라가는 방식을 이용할 수 있습니다. 이 때 '뒤에서부터 찾아 올라간다'는 개념이 'DESCENDING'입니다. 이전에 실행한 bno의 역순으로 데이터를 가져올 때의 실행 계획을 다시 한 번 살펴보겠습니다.

실행 계획을 살펴보면 PK_BOARD라는 인덱스를 이용하는데 DESCENDING을 하고 있는 것을 볼 수있습니다. 인덱스를 역순으로 찾기 때문에 가장 먼저 찾은 bno 값은 가장 큰 값을 가진 데이터가 됩니다. 이후에는 테이블에 접근해서 데이터를 가져오게 되는데, 이런 과정이 반복되면 정렬을 하지 않아도 동일하게 정렬된 결과를 볼 수 있게 됩니다. 하나의 예를 더 생각해보면, 만일 사용자가 'bno의 순서로 정렬해 달라'고 요구하는 상황이라면 PK_BOARD인덱스가 앞에서부터 찾아서 내려가는 구조를 이용하는 것이 효율적입니다. SQL Developer를 이용해서 실행해 보면 아래와 같은 실행 계획이 수립되는 것을 볼 수 있습니다.

 

실행 계획상으로는 PK_BOARD 인덱스를 먼저 접근하고, TBL_BOARD를 이용하는 것을 볼 수 있습니다. SORT가 없기 때문에 0초에 가까운 성능을 보여줍니다. 실무에서도 데이터의 양이많고 정렬이 필요한 상황이라면 우선적으로 생각하는 것이 '인덱스'를 작성하는 것입니다. 데이터의 양이 수천,수만개 정도의 정렬은 그다지 부하가 걸리지 않지만 그 이상의 데이터를 처리해야 하는 상황이라면 정렬을 안할 수 있는 방법에 대해서 고민해야 합니다.

 

-인덱스와 오라클 힌트(hint)

웹페이지의 목록은 주로 시간의 역순으로 정렬된 결과를 보여줍니다. 최신 데이터가 가장 중요하기 때문에 시간의 역순으로 정렬해서 최신 게시물들을 보여주게 됩니다. 이 경우 개발자의 입장에서는 정렬을 안 하는 방식으로 select문을 실행하고 싶어 하는데 오라클은 이때 '힌트(hint)'라는 것을 사용할 수 있습니다. 힌트는 말 그대로 데이터베이스에 지금 내가 전달한 select문을 이렇게 실행 해 주면 좋겠습니다. 라는 힌트입니다. 힌트는 구문에서 에러가 나도 전혀 SQL실행에 지장을 주지 않습니다. 따라서 힌트를 이용한 select문을 작성한 후에는 실행 계획을 통해서 개발자가 원하는 대로 SQL이 실행되는 지를 확인하는 습관을 가져야 합니다. 게시물 목록은 최신 게시글이 위로 올라와야 하므로 'order by bno desc' 구문을 추가해야하는데 문제는 데이터베이스 상황에 따라서 테이블의 모든 데이터를 정렬(SORT)하는 방식으로도 동작할 수 있다는 것입니다. 반면에 힌트는 개발자가 데이터베이스에 어떤 방식으로 실행해 줘야 하는지를 명시하기 때문에 조금 강제성이 부여되는 방식입니다. 

select /*+INDEX_DESC(tbl_board pk_board) */* from tbl_board;

select * from tbl_board order by bno desc ;

* 다음 2개의 SQL은 동일한 출력 결과를 보여주는 SQL문입니다. 그러나 1번째 select문은 order by 조건이 없어도 동일한 결과가 나온 것에 주목해야 합니다. select문에서 힌트를 부여 했는데 힌트의 내용이 'tbl_board 테이블에 pk_board 인덱스를 역순으로 이용해 줄 것' 이므로 실행 계획에서 이를 활용하고 있는 것을 확인할 수 있습니다.

오라클 데이터베이스에서 사용할 수 있는 힌트는 여러종류가 있는데 자주 사용하는 몇가지만 언급하겠습니다.

 

-힌트 사용 문법

select문을 작성할 때 힌트는 잘못 작성되어도 실행할 때는 무시되기만 하고 별도의 에러는 발생하지 않습니다. 우선 힌트를 사용할 때에는 다음과 같은 문법을 사용합니다.

select /*+HINT_NAME(param....) */ column name,....from table_name;

*힌트 구문은 '/*+' 로 시작하고 '*/'로 마무리됩니다. 힌트 자체는 SQL로 처리되지 않기 때문에 뒤에 칼럼명이 나오더라도 별도의 ',' 로 처리되지 않습니다.

 

-FULL 힌트

 

힌트 중에는 해당 select문을 실행할 때 테이블 전체를 스캔할 것으로 명시하는 FULL 힌트가 있습니다. FULL힌트는 테이블의 모든 데이터를 스캔하기 때문에 데이터가 많을 때는 상당히 느리게 실행됩니다. 예를 들어 tbl_board테이블을 FULL 스캔하도록 하고, 이 상태에서 정렬을 하려면 다음과 같이 작성 할 수 있습니다.

실행 계획을 보면 TBL_BOARD를 FULL로 접근하고, 다시 SORT가 적용된 것을 볼 수 있습니다. 실행시간 역시 SORT를 사용했기 때문에 index에 비해서는 느립니다. 

 

-INDEX_ASC,INDEX_DESC 힌트

 

흔히 목록 페이지에서 가장 많이 사용하는 힌트는 인덱스와 관련된 'INDEX_ASC,INDEX_DESC' 힌트 입니다. ASC/DESC에서 알 수 있듯이 인덱스를 순서대로 이용할 것인지 역순으로 이용할 것인지를 지정하는 것입니다. INDEX_ASC/DESC 힌트는 주로 'order by'를 위해서 사용한다고 생각하며 됩니다. 인덱스 자체가 정렬을 해 둔 상태이므로 이를 통해서 SORT 과정을 생략하기 위한 용도 입니다.

INDEX_ASC/DESC 힌트는 테이블 이름과 인덱스 이름을 같이 파라미터로 사용합니다.

select /*+ INDEX_DESC(tbl_board pk_board) */* from tbl_board;

 

-ROWNUM과 인터뷰

전체가 아닌 필요한 만큼의 데이터를 가져오는 방식에 대해서 말하겠습니다. 오라클 데이터베이스는 페이지 처리를 위해서 ROWNUM이라는 특별한 키워드를 사용해서 데이터에 순번을 붙여 사용합니다. ROWNUM은 쉽게 생각해서 SQL이 실행된 결과에 넘버링을 해준다고 생각하면 됩니다. 모든 SELECT문에는 ROWNUM이라는 변수를 이용해서 해당 데이터가 몇 번째로 나오는지 알아낼 수 있습니다. ROWNUM은 실제 데이터가 아니라 테이블에서 데이터를 추출한 후에 처리되는 변수이므로 상황에 따라서 그 값이 매번 달라질 수 있습니다.  우선 아무조건을 적용하지 않고 tbl_board 테이블에 접근하고 각 데이터에 ROWNUM을 적용하면 다음과 같이 작성할 수 있습니다.

select ROWNUM rn,bno,title from tbl_board;

ROWNUM은 테이블에는 존재하지 않고 테이블에서 가져온 데이터를 이용해서 번호를 매기는 방식으로 위의 결과는 테이블에서 가장 먼저 가져올 수 있는 데이터들을 꺼내서 번호를 붙여주고 있습니다. 이 때 번호는 현재 데이터베이스의 상황에 따라서 저장된 데이터를 로딩하는 것이므로 실습환경에 따라 다른 값이 나오게 됩니다. 16번 데이터는 첫번째로 꺼내진 데이터라고 해석할 수 있습니다. 만일 테이블에서 데이터를 가져온 후에 정렬을 하게 된다면 16번의 ROWNUM 값은 동일하게 3이 됩니다.

select /*+ FULL(tbl_board) */ rownum rn,bno,title from tbl_board where bno > 0 order by bno;

 

이의 SQL은 FULL 힌트를 이용해서 전체 데이터를 조회하고 다시 정렬하는 방식입니다. 결과를 보면 16번데이터는 똑같이 1번째로 접근한 데이터이지만 정렬 과정에서 뒤쪽으로 밀리는 것을 볼 수 있습니다. 이를 통해서 알 수 있는 것은 ROWNUM이라는 것은 데이터를 가져올 때 적용되는 것이고 이 후에 정렬되는 과정에서는 ROWNUM이 변경되지 않는다는 것입니다. 다른 말로는 정렬이 나중에 처리된다는 것입니다.

-인덱스를 이용한 접근 시 ROWNUM

ROWNUM의 의미가 테이블에서 데이터를 가져오면서 붙는 번호라는 사실을 기억해 보면 결국 문제는 테이블에 어떤 순서로 접근하는가에 따라서 ROWNUM 값은 바뀔 수 있다는 뜻이 됩니다. 다시 말해, 위의 경우는 우선 FULL로 접근해서 16번 데이터를 찾았고 이후에 정렬을 하는데 이미 데이터는 다 가져온 상태이므로 ROWNUM에는 아무런 영향을 주지 않습니다.

만일 PK_BOARD 인덱스를 통해서 접근한다면 다음과 같은 과정으로 접근합니다.

1) PK_BOARD 인덱스를 통해서 테이블에 접근

2) 접근한 데이터에 ROWNUM 부여

1)의 과정에서 이미 정렬이 되어있기 때문에 16번의 접근 순서는 첫번째가 아니라 한참 뒤일 것입니다. 이 경우 ROWNUM은 전혀 다른값을 가지게 됩니다.

select /*+ INDEX_ASC(tbl_board pk_board) */ rownum rn,bno,title,content from tbl_board;

ROWNUM의 값이 1번 -> 16 으로 변경되었습니다.

만일 게시물의 역순으로 테이블을 접근하게 된다면 16번의 ROWNUM 값은 접근하는 순서가 뒤쪽이기 때문에 데이터가 많을 경우 엄청나게 큰값이 나오게 될 것입니다. ROWNUM은 데이터에 접근하는 순서이기 때문에 가장 먼저 접근하는 데이터가 1번이 되는데. 이를 이용하면 테이블을 bno의 역순으로 접근해서 bno값이 가장 큰 데이터가 ROWNUM 값이 1이 되도록 작성할 수 있습니다.

select /*+ INDEX_DESC(tbl_board pk_board) */ rownum rn,bno,title,content from tbl_board where bno>0;

위의 SQL은 PK_BOARD 인덱스 역으로 타면서 테이블에 접근했기 때문에 bno값이 가장 높은 데이터를 가장 먼저 가져오게 됩니다. 이 방식을 이용하면 각 게시물을 정렬하면서 순번을 매겨줄 수 있는데, 1페이지의 경우는 위의 그림에서 RN이라는 칼럼의 값이 1부터10에 해당한다고 볼 수 있습니다.

 

-페이지 번호 1,2의 데이터

한 페이지당 10개의 데이터를 출력한다고 가정하면 ROWNUM 조건을 Where 구문에 추가해서 다음과 같이 작성할 수 있습니다.

select /*+ INDEX_DESC(tbl_board pk_board) */ rownum rn,bno,title,content from tbl_board where rownum <=10;

실행 계획

SQL의 실행 계획을 통해서 PK_BOARD 인덱스를 역순으로 접근하는 것을 확인할 수 있습니다. WHERE 조건에서 특이하게 ROWNUM 조건은 테이블을 접근할 때 필터링 조건으로 적용된 것을 볼 수 있습니다. 단, 1페이지 데이터를 구했다면 흔히 동일한 방식으로 2페이지 데이터를 구할 수 있다고 생각하는데 원하는 결과는 나타나지 않습니다.

select /*+ INDEX_DESC(tbl_board pk_board) */ rownum rn,bno,title,content from tbl_board where rownum > 10 and rownum <=20;

실행결과

아무런 데이터가 나오지 않음!

실행계획

*실행 계획을 보면 그 해답을 찾을 수 있는데 실행 계획은 안쪽부터 바깥쪽으로,위에서 아래로 보게 되므로 위의 실행 계획은 우선 ROWNUM >10, 데이터들을 찾게 됩니다. 문제는 TBL_BOARD에 처음으로 나오는 ROWNUM의 값이 1이라는 것입니다. TBL_BOARD에서 데이터를 찾고 ROWNUM값이 1이 된 데이터는 where조건에 의해서 무효화됩니다. 이후에 다시 다른 데이터를 가져오면 새로운 데이터가 첫 번째 데이터가 되므로 다시 ROWNUM은 1이 됩니다. 이 과정이 반복되면 ROWNUM 값은 항상 1로 만들어지고 없어지는 과정이 반복되므로 테이블의 모든 데이터를 찾아내지만 결과는 아무것도 나이조 않게 됩니다. 이러한 이유로 SQL을 작성할 때 ROWNUM 조건은 반드시 1이 포함되어야 합니다.

SQL에 ROWNUM 조건이 1이 포함되도록 다음과 같이 수정해보면 결과가 나오는 것을 볼 수 있습니다.

select /*+ INDEX_DESC(tbl_board pk_board) */ rownum rn,bno,title,content from tbl_board where rownum <=20;

 달라진 점은 1을 포함하도록 변경한 것뿐입니다. 위의 SQL 결과는 역순으로 데이터를 20개 가져오게 됩니다.

-인라인뷰(in-line View) 처리

10개씩 목록을 출력하는 경우 2페이지의 데이터 20개를 가져오는 데는 성공했지만, 1페이지의 내용이 같이 출력되는 문제가 있으므로 마지막으로 이 문제를 수정해야 합니다. 이 문제를 해결하기 위해서는 인라인뷰라는 것을 이용하는데 인라인뷰는 'SELECT문 안쪽 FROM에 다시 SELECT문'으로 이해할 수 있습니다. 인라인 뷰는 논리적으로는 어떤 결과를 구하는 SELECT문이 있고, 그 결과를 다시 대상으로 삼아서 SELECT를 하는 것입니다. 데이터베이스는 테이블이나 인덱스와 같이 뷰(View)라는 개념이 존재합니다. 뷰는 일종의 창문 같은 개념으로 복잡한 SELECT 처리를 하나의 뷰로 생성하고, 사용자들은 뷰를 통해서 복잡하게 만들어진 결과를 마치 하나의 테이블처럼 쉽게 조회한다는 개념입니다. 인라인 뷰는  이러한 뷰의 작성을 별도로 작성하지 않고 말 그대로 FROM 구문 안에 바로 작성하는 형태입니다.

SELECT ... FROM(SELECT... FROM...(인라인뷰))

외부에서 SELECT문은 인라인뷰로 작성된 결과를 마치 하나의 테이블처럼 사용합니다. 예를 들어 위의 경우 20개의 데이터를 가져오는 SQL을 하나의 테이블처럼 간주하고 바깥쪽에서 추가적인 처리를 하는 것입니다.

만일 위의 결과를 하나의 테이블로 보면 해당 테이블은 RN,BNO,TITLE,CONTENT라는 칼럼을 가지는 테이블이 됩니다. 이 경우 이 테이블에서 원하는 것은 RN칼럼 값이 10보다 큰 데이터만 가져오면 됩니다. 인라인뷰를 적용한 2페이지 데이터의 처리는 아래와 같이 작성될 수 있습니다.

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;

기존의 SQL과 비교해 보면 20개의 데이터를 가져온 후 2페이지에 해당하는 10개만을 추출하는 방식으로 구현 됩니다.

이 과정을 정리하면 다음과 같은 순서입니다.

-필요한 순서로 정렬된 데이터에 ROWNUM을 붙인다.

-처음부터 해당 페이지의 데이터를 ROWNUM <= 30 과 같은 조건을 이용해서 구한다.

-구해놓은 데이터를 하나의 테이블처럼 간주하고 인라인뷰로 처리한다.

-인라인뷰에서 필요한 데이터를 남긴다.

728x90
Comments