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

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

12.1 order by의 문제

  • 프로그램을 이용해 정렬을 하면 데이터의 양이 많을수록 정렬이라는 작업이 많은 리소스를 소모하는지 알 수 있다.
  • 데이터베이스는 경우에 따라 수백만 혹은 천 만개 이상의 데이터를 처리하기 때문에 이 경우 정렬을 하게 되면 엄청난 시간과 리소스를 소모하게 된다.
  • 데이터 베이스를 이용할 때 웹이나 애플리케이션에 가장 신경 쓰는 부분은 1) 빠르게 처리 되는 것, 2) 필요한 양 만큼만 데이터를 가져오는 것이다.
  • 거의 모든 웹페이지에서 페이징을 하는 이유는 최소한의 필요한 데이터만을 가져와 빠르게 화면에 보여주기 위함이다.
  • 만일 수백 만개의 데이터를 매번 정렬을 해야 하는 상황이라면 사용자는 정렬된 결과를 볼 때까지 오랜 시간을 기다려야만 하고, 특히 웹에서 동시에 여러 명의 사용자가 정렬이 필요한 데이터를 요청하게 되면시스템에 많은 부하가 걸리게 되고 연결 가능한 커넥션의 개수가 점점 줄어 서비스가 멈추는 상황을 초래하게 된다.
  • 빠르게 동작하는 SQL 을 위해 먼저 order by를 이용하는 작업을 가능하면 하지 말아야 한다.
  • order by는 데이터가 많은 경우 엄청난 성능의 저하를 가져오기 때문에 1) 데이터가 적은 경우, 2) 정렬을 빠르게 할 수 있는 방법이 있는 경우가 아니라면 order by는 주의해야 한다.

12.1.1 실행 계획과 order by

  • 오라클의 페이징 처리를 제대로 이해하기 위해 반드시 알아야 하는 것이 실행 계획(execution plan)이다.
  • 실행 계획은 'SQL을 데이터베이스에서 어떻게 처리할 것인가?'에 대한 것이다.
  • SQL이 데이터베이스에서 전달되면 데이터베이스는 여러 단계를 거쳐 해당 SQL을 어떤 순서와 방식으로 처리할 것인지 계획을 세우게 된다.
  • 데이터베이스에 전달된 SQL문은 아래와 같은 과정을 거쳐 처리된다.
  • SQL 파싱 단계에서는 SQL 구문에 오류가 있는지 SQL을 실행해야 하는 대상 객체(테이블, 제약조건, 권한 등)가 존재하는지를 검사한다.
  • SQL 최적화 단계에서는 SQL이 실행되는데 필요한 비용(cos)을 계산하게 된다.
  • 이 계산된 값을 기초로 해서 어떤 방식으로 실행하는 것이 가장 좋다는 것을 판단하는 '실행 계획'을 세우게 된다.
  • SQL 실행 단계에서는 세워진 실행 계획을 통해 메모리상에서 데이터를 읽거나 물리적인 공간에서 데이터를 로딩하는 등의 작업을 하게 된다.
  • 개발자들은 도구를 이용하거나 SQL Plus 등을 이용해 특정한 SQL에 대한 실행 계획을 알아볼 수 있다.
  • SQL Developer에서 간단히 버튼을 클릭해 실행 계획을 확인할 수 있다.
  • 예를 들어, '게시물 번호의 역순으로 출력하라'는 처리를 한다면 SQL Developer에서 다음과 같이 처리할 수 있다.
  • 상단의 버튼 중에는 SQL에 대해 '실행 계획'을 쉽게 볼 수 있도록 버튼이 제공된다.
  • 실행 계획을 보면 트리 구조로 방금 전 실행한 SQL이 어떻게 처리된 것인지 알려준다.
  • 흔히 SQL 튜닝이라 하는 작업은 이를 보고 어떤 방식이 더 효과적인지 판단해 수정하게 된다.
  • 실행 계획을 보는 방법은 '안쪽에서 바깥쪽으로, 위에서 아래로' 보면 된다.
  • 위 그림을 해석하면, 'TBL_BOARD' 테이블을 'FULL'로 접근하고 정렬했다는 것을 의미한다.
  • 'FULL'이라는 의미는 테이블 내의 모든 데이터를 스캔했다는 의미다.
  • 실행 계획을 세우는 것은 데이터베이스에서 하는 역할이기 때문에 데이터의 양이나 제약 조건 등의 여러 상황에 따라 데이터베이스는 실행 계획을 다르게 작성한다.
  • 테스트를 위해 데이터가 좀 많아지도록 아래의 SQL을 여러 번 실행해서 데이터를 수백 만개로 만든 후에 커밋을 한다.
-- 재귀 복사를 통해 데이터의 개수를 늘린다. 반복해서 여러 번 실행
INSERT INTO TBL_BOARD (BNO, TITLE, CONTENT, WRITER)
(SELECT SEQ_BOARD.NEXTVAL, TITLE, CONTENT, WRITER FROM TBL_BOARD);
  • 위의 INSERT 문을 여러 번 실행하게 되면 현재 TBL_BOARD 테이블의 데이터 수만큼 다시 INSERT가 진행된다.
  • 결과를 보면 INSERT문을 실행할 때마다 2배씩 데이터가 늘어나게 된다.
  • 아래 그림은 여러 번 실행해 한 번에 22만개의 데이터를 복사해 넣는 것을 보여준다. (원래 데이터 22만건 + 22만건 = 44건)
  • COMMIT 후에 'SELECT COUNT(*) FROM TBL_BOARD'를 실행해 보면 데이터의 수가 엄청 늘어난 것을 확인할 수 있다.
  • 데이터가 많아지면 정렬에 그만큼의 시간을 소모하게 된다.
  • 고의적으로 bno라는 칼럼의 값에다 1을 추가한 값을 역순으로 정렬하는 SQL을 만든다면 다음과 같다.
SELECT * FROM TBL_BOARD ORDER BY BNO + 1 DESC;
  • 연산 작업이 추가되기는 했지만 SQL문의 결과가 나오는데 시간이 22초 걸린다. (실행 시간은 현재 시스템의 상황이나 데이터베이스의 상황에 따라 차이가 난다. 반복적으로 몇 번 실행하면 데이터베이스가 메모리상에 보간하는 데이터를 가져오는 상황이 되고 대략 1초대에 결과가 나올 수 있다.)
  • 위의 SQL을 실행한 결과는 테이블 전체를 스캔하는데, 실행 계획을 살펴보면 TBL_BOARD를 'FULL'로 스캔했고, 바깥쪽으로 가면서 'SORT'가 일어난다.
  • 이 때 가장 많은 시간을 소모하는 작업은 정렬하는 작업이다.
  • 위의 SQL에서 'ORDER BY BNO + 1 DESC'라는 조건에서 '+1'을 하는 것은 정렬에 아무런 도움을 주지 않으므로 아래와 같이 SQL을 수정해 실행한다.
SELECT * FROM TBL_BOARD ORDER BY BNO DESC;
  • 연산 차이가 있지만, 실행에 걸리는 시간은 차이가 많이 나게 된다.
  • 이전에 22초가 걸리던 작업이 거의 0초만에 실행되는 차이가 난다.
  • 이 결과의 차이에는 실행 계획도 기존과 다르게 동작한다.
  • 기존의 SQL이 TBL_BOARD 테이블 전체를 스캔했지만, 이번에는 PK_BOARD라는 것을 이요해 접근하고 기존과 달리 맨 위의 SORT 과정이 없는 것을 볼 수 있다.
  • 이것을 이해하려면 데이터베이스의 인덱스에 대해 알아야 한다.
profile
한 걸음 한 걸음 나아가는 개발자

0개의 댓글