인덱스 종류와 선택


인덱스는 데이터베이스 물리 설계에서 매우 중요한 위치를 차지한다. 같은 데이터베이스라 하더라도 인덱스 활용 전략에 따라서 매우 많은 성능의 차이를 보이기 때문이다. 여기에서는 인덱스의 종류와 어떤 경우에 어떤 인덱스를 적용해야 하는지 알아보도록 한다.
일반적인 RDBMS에서의 인덱스는 다음과 같이 두 가지 종류로 나뉜다.

● 스파스 인덱스(Sparse Index) : 해당 레코드 존재 페이지를 가리키는 포인터를 저장하는 인덱스
● 덴스 인덱스(Dense Index) : 해당 레코드를 가리키는 포인터를 저장하는 인덱스
* 힙(Heap) : 데이터가 입력되는 순서에 따라 정렬되어 쌓이는 테이블 구조

페이지에는 여러 개의 레코드가 있으므로 일반적인 경우는 스파스 인덱스가 유리하다. 하지만 레코드의 길이가 페이지의 크기와 비슷한 경우라면 스파스 인덱스는 덴스 구조보다 디스크 액세스를 많이 수행하게 되므로 성능이 떨어진다. 물론 늘 그런 것은 아니며 DBMS가 어떻게 구성되었느냐에 따라 다른 결과가 나타날 수도 있다. 만약 해당 DBMS에서 데이터 행 체인(Row Chain)이 발생된다면 불리할 수 있으나 체인을 지원하지 않고, 행 마이그레이션(Row Migration)만 지원한다면 큰 차이가 없다. 어떤 DBMS는 최소 입/출력 단위에 데이터를 꽉꽉 채울 수 있는 반면, 어떤 DBMS는 데이터를 모두 채울 수 없기 때문에 두 인덱스 방식의 장/단점 비교는 조건이 잘 주어져야 가능하다.

<그림 9> 스파스 인덱스와 덴스 인덱스


상용 DBMS는 <표 1>과 같이 다양한 종류의 인덱스를 지원한다. 오라클에서는 인덱스 조직 테이블(Indexed-Organized Table)이 지원되는데 이는 MS SQL 서버의 클러스터드 인덱스를 가진 테이블과 비슷한 구조로 생각하면 되며 스파스 인덱스 방식이라고 생각해도 무방하다.

<그림10> 힙(Heap)에서의 트랜잭션 집중


또 한 가지 중요한 사실은 스파스 인덱스와 덴스 인덱스가 혼재되어 있을 경우 나누어 저장하는 것이 효과적이라는 점이다.
데 이터베이스 시스템과 떼어놓을 수 없는 중요한 사항이 바로 트랜잭션이다. 작은 트랜잭션 하나가 잠금을 얻으면 잠금 수준에 따라서 많은 양의 트랜잭션이 대기할 수도 있다. 힙과 같은 구조는 데이터가 들어오는 순서대로 쌓이기 때문에 특정 페이지(최소 입/출력 단위) 잠금이 걸린다면 해당 페이지에 접근하고 있는 트랜잭션은 모두 대기 상태가 된다. 이러한 경우 레코드 단위의 잠금을 걸면 해결되지만, 레코드의 입력이 너무 빈번하게 발생한다면 결국 병목현상이 발생할 수밖에 없다. 그러므로 MS SQL Server와 같은 경우에는 테이블에 클러스터드 인덱스(Sparse Index)를 생성하기를 권한다.
하지만 클러스터드 인덱스는 추가(Insert), 갱신(Update), 삭제(Delete)할 때마다 데이터를 재정렬해야 하기 때문에 부하가 많이 걸린다. 범위 연산이나 한 번에 많은 데이터를 가져와야 하는 경우라면 클러스터드 인덱스를 생성해야 한다. 일반적인 OLTP시스템이라면 클러스터드 인덱스는 권장사항이다. 그러나 특정 행 단위 위주로 접근하는 경우라면 클러스터드 인덱스는 사용하지 않는 편이 좋다. 조회 성능이 중요한 클러스터드 인덱스 생성은 적극 고려해야 할 대상이다.
만약 시간이 된다면 주로 사용하는 인덱스의 순서에 맞추어 테이블의 데이터를 다시 넣어두면 성능을 높이는데 도움이 된다. 또한 추가, 갱신, 삭제 시 인덱스도 같이 변경되어야 하므로 MS SQL Server는 PAD_INDEX, FILLFACTOR 옵션을 인덱스 생성, 변경 시 제공하고 있다. 이 두 옵션은 인덱스의 저장 공간을 비워두어 추가적인 작업(Insert 등)에 대해 인덱스의 재조정을 막는 역할을 한다.

+ Recent posts