Part 12. 오라클 데이터베이스 페이징 처리
12.3 인덱스를 이용한 정렬
- 인덱스에서 가장 중요한 개념 중 하나는 '정렬이 되어 잇다는 점'이다.
- 정렬이 이미 되어 있는 상태이므로 데이터를 찾아내 이들을 SORT 하는 과정을 생략할 수 있다.
- 'bno의 역순으로 정렬한 결과'를 원한다면 이미 정렬된 인덱스를 이용해 뒤에서부터 찾아 올라가는 방식을 이용할 수 있다.
- 이 때 '뒤에서부터 찾아 올라간다'는 개념이 'DESCENDING'이다.
- 이전에 실행한 bno의 역순으로 데이터를 가져올 때의 실행 계획을 다시 살펴보면
- 실행 계획을 살펴보년 PK_BOARD라는 인덱스를 이용하는데 DESCENDING을 하고 있는 것을 볼 수 있다.
- 이를 그림으로 표현하면 아래와 같이 표현할 수 있다.
- 인덱스를 역순으로 찾기 때문에 가정 먼저 찾은 bno 값은 가장 큰 값을 가진 데이터가 된다.
- 이후에는 테이블에 접근해 데이터를 가져오게 되는데, 이런 과정이 반복되면 정렬을 하지 않아도 동일하게 정렬된 결과를 볼 수 있게 된다.
- 하나의 예를 더 생각해 보면, 만일 사용자가 'bno의 순서로 정렬해 달라'고 요구하는 상황이라면 PK_BOARD 인덱스가 앞에서부터 찾아서 내려가는 구조를 이용하는 것이 효율적이다.
- SQL Developer를 이용해 실행해 보면 아래와 같은 실행 계획이 수립된다.
- 실행 계획상으로 PK_BOARD 인덱스를 먼저 접근하고, TBL_BOARD를 이용하는 것을 볼 수 있다.
- SORT가 없기 때문에 0초에 가까운 성능을 보여준다.
- 실무에서도 데이터의 양이 많고 정렬이 필요한 상황이라면 우선적으로 생각하는 것이 '인덱스'를 작성하는 것이다.
- 데이터의 양이 수천, 수만개 정도의 정렬은 그다지 부하가 걸리지 않지만 그 이상의 데이터를 처리해야 하는 상황이라면 정렬을 안할 수 있는 방법에 대해 고민해야 한다.
12.3.1 인덱스와 오라클 힌트(hint)
- 웹페이지의 목록은 주로 시간의 역순으로 정렬된 결과를 보여준다.
- 최신 데이터가 가장 중요하기 때문에 시간의 역순으로 정렬해 최신 게시물들을 보여주게 된다.
- 이 경우 개발자의 입장에서 정렬을 안 하는 방시긍로 select 문을 실행하고 싶어한다.
- 오라클은 select문을 전달할 때 '힌트(hint)'라는 것을 사용할 수 있다.
- 힌트는 데이터베이스에 '지금 내가 전달한 select문을 이렇게 실행해 주면 좋겠다'라는 힌트다.
- 힌트는 특이하게 select문을 어떻게 처리하는지에 대한 얘기일 뿐이므로 힌트 구문에서 에러가 나도 전혀 SQL 실행헤 지장을 주지 않는다.
- 따라서 힌트를 이용한 select문을 작성한 후에는 실행 계획을 통해 개발자가 원하는 대로 SQL이 실행되는지 확인하는 습관을 가져야 한다.
- 게시물 목록은 반드시 시간의 역순으로 나와야 하기 때문에 SQL에서는 'order by bno desc'와 같은 구문을 추가할 수 있다.
- 문제는 'order by bno desc'와 같은 조건은 데이터베이스 상황에 따라 테이블의 모든 데이터를 정렬하는 방식으로도 동작할 수 있다는 점이다.
- 반면에 힌트는 개발자가 데이터베이스에 어떤 방식으로 실행해 줘야 하는지를 명시하기 때문에 조금 강제성이 부여되는 방식이다.
SELECT * FROM TBL_BOARD ORDER BY BNO DESC;
SELECT /*+INDEX_DESC (TBL_BOARD PK_BOARD) */*
FROM TBL_BOARD;
- 위의 두 SQL은 동일한 결과를 생성하는 SQL이다.
- 두 번째 SELECT문은 ORDER BY 조건이 없어도 동일한 결과가 나온 것에 주목해야 한다.
- SELECT문에서 힌트를 부여했는데 힌트의 내용이 'TBL_BOARD 테이블에 PK_BOARD 인덱스를 역순으로 이용해 줄 것'이므로 실행 계획에서 이를 활용하고 있는 것을 확인할 수 있다.
- 오라클 데이터베이스에서 사용할 수 있는 힌트는 여러 종류가 있다.
12.3.2 힌트 사용 문법
- SELECT 문을 작성할 때 힌트는 잘못 작성되어도 실행할 때는 무시되기만 하고 별도의 에러는 발생하지 않는다.
- 우선 힌트를 사용할 때에는 다음과 같은 문법을 사용한다.
SELECT
/*+ Hint name (param...) */ column name, ...
FROM
table name
- 힌트 구문은 '/+'로 시작하고, '/'로 마무리 된다.
- 힌트 자체는 SQL로 처리되지 않기 때문에 위의 문법처럼 칼럼명이 나오더라도 별도의 ','로 처리되지 않는다.
12.3.3 FULL 힌트
- 힌트 중에는 해당 SELECT문을 실행할 때 테이블 전체를 스캔할 것으로 명시하는 FULL 힌트가 있다.
- FULL 힌트는 테이블의 모든 데이터를 스캔하기 때문에 데이터가 많을 때는 상당히 느리게 실행된다.
- 예를 들어, TBL_BOARD 테이블을 FULL 스캔하도록 하고, 이 상태에서 정렬을 하려면 다음과 같이 작성할 수 있다.
SELECT /*+ FULL(TBL_BOARD) */ * FROM TBL_BOARD ORDER BY BNO DESC;
- 실행 계획을 보면 TBL_BOARD를 FULL로 접근하고, 다시 SORT가 적용된 것을 볼 수 있다.
- 실행 시간 역시 29초 이상으로 오래 걸리는 것을 볼 수 있다.(시간은 현재 데이터베이스의 상황에 따라 다르게 나오지만, 인덱스를 사용했을 때에 비해 느리다는 점을 확인할 수 있다.)
12.3.4 INDEX_ASC, INDEX_DESC 힌트
- 흔히 목록 페이지에서 가장 많이 사용되는 힌트는 인덱스와 관련된 'INDEX_ASC, INDEX_DESC' 힌트다.
- ASC/DESC에서 알 수 있듯이 인덱스를 순서대로 이용할 것인지 역순으로 이용할 것인지를 지정하는 것이다.
- INDEX_ASC/DESC 힌트는 주로 'order by'를 위해 사용한다고 생각하면 된다.
- 인덱스 자체가 정렬을 해둔 상태이므로 이를 통해 SORT 과정을 생략하기 위한 용도다.
- INDEX_ASC/DESC 힌트는 테이블 이름과 인덱스 이름을 같이 파라미터로 사용한다.
SELECT /*+ INDEX_ASC(TBL_BOARD PK_BOARD) */ * FROM TBL_BOARD
WHERE BNO > 0;
- INDEX_ASC/DESC를 이용하는 경우에는 동일한 조건의 order by 구문을 작성하지 않아도 된다.
- 예를 들어, 위의 SQL에서 아무런 order by 조건이 없어도 bno의 순번을 통해 접근하기 때문에 'order by bno asc' 구문은 필요하지 않다.