본문 바로가기

Database

[Database] 인덱스 스플릿 (Index Split)

반응형

 


 

인덱스 스플릿(Index Split) 이란?

데이터베이스에서 B-Tree 구조에서 인덱스를 관리할 때 발생하는 현상이다.
인덱스 스플릿은 인덱스 페이지에 더 이상 데이터를 추가할 공간이 없을 때 페이지를 나누어 새로운 데이터를 삽입할 수 있도록 하는 작업이다.

 

인덱스 스플릿(Index Split) 과정

1. 새로운 데이터 삽입 시도
2. 공간 부족 감지
3. 페이지 분할 발생
4. 부모 노드 업데이트

아래 예시를 통해 인덱스 스플릿 현상을 확인해보자.

Step 1. 기존 인덱스 페이지 상태

+---------------------+
|     Index Page      |
|---------------------|
|  1 | 2 | 3 | 4 | 5  |
+---------------------+

하나의 인덱스 페이지가 8KB 라고 가정해보자. 위와 같이 8KB 가 모두 가득찬 인덱스 페이지가 있다.

 

Step 2. 새로운 6번 인덱스 데이터 삽입 시도

+---------------------+
|     Index Page      |
|---------------------|
|  1 | 2 | 3 | 4 | 5  | <- 6
+---------------------+

이 때, 6 이라는 새로운 인덱스 값을 삽입하려고 한다.
하지만 현재 인덱스 페이지에는 공간이 없으므로 이 때 인덱스 스플릿 이 발생하게 된다.

Step 3. 인덱스 스플릿(Index Split) 발생

+--------------------------+      +--------------------------+
|       Index Page 1       |      |       Index Page 2       |
|--------------------------|      |--------------------------|
|       1 | 2 | 3          |      |       4 | 5 | 6          |
+--------------------------+      +--------------------------+

인덱스 스플릿이 발생하여 페이지가 두개로 나뉘게 된다.

그런데 왜 Index Page 2 에 6 이라는 데이터가 추가되는 게 아니라 이렇게 Index Page 1 / Index Page 2 가 균형적으로 나뉘냐?
이것은 B-Tree 구조 특성때문이다. B-Tre 구조는 각 노드(페이지)가 균형을 이루도록 설계가 되어 있다.
그래서 인덱스 스플릿이 발생할 때, 새로운 페이지에 6번 데이터만 추가되는 게 아니라 균형 잡힌 방식으로 재분배가 된다.

 

Step 4. 부모 노드(페이지) 업데이트

         +----------------------+
         |     Parent Node      |
         |----------------------|
         |  Pointer to Page 1   |-------->  +--------------------------+
         |  Pointer to Page 2   |-------->  |       Index Page 1       |
         +----------------------+           |--------------------------|
                                             |       1 | 2 | 3          |
                                             +--------------------------+

                                             +--------------------------+
                                             |       Index Page 2       |
                                             |--------------------------|
                                             |       4 | 5 | 6          |
                                             +--------------------------+

변경된 페이지를 토대로 부모 노드에 변경된 페이지의 포인터 정보를 업데이트하고, 새로운 페이지의 정보도 추가한다.
*만약 부모 노드도 가득 차 있으면 추가적으로 부모 노드도 스플릿이 발생할 수 있다.

 

인덱스 스플릿(Index Split) 문제

1. 디스크 I/O 증가

인덱스 스플릿은 새로운 페이지를 생성하고 데이터를 재배치하는 작업을 수반하면서 디스크 I/O 를 증가시킨다.

2. 성능 저하

스플릿 과정에서 여러 페이지를 읽고 쓰는 작업이 필요하여 삽입 작업의 속도를 저하시키며, 스플릿이 자주 발생하면 인덱스 트리가 커질 수 있다. 이는 데이터 검색 시 더 많은 페이지를 탐색해야 함을 의미한다. 

3. 인덱스 단편화(Index Fragmentation) 발생

스플릿 후 페이지는 부분적으로만 채워지기 때문에, 페이지 단편화가 발생할 수 있다. 이는 저장 공간의 비효율적인 사용으로 이어진다.

인덱스 단편화(Index Fragmentation) 이란?
인덱스가 비효율적으로 정렬되고 분산되는 현상을 의미한다. 빈번한 DML 작업으로 발생한다. 분산이 된 인덱스는 데이터를 찾기 위해 더 많은 디스크 페이지를 읽어야 하여 디스크I/O 를 증가시키고, 더 많은 페이지를 찾고 읽어야하기 때문에 쿼리 실행 시간이 증가하게 된다.

 

인덱스 스플릿(Index Split) 예방

1. Fill Factor 조정

인덱스 생성 시 Fill Factor 를 낮게 설정하여 페이지 스플릿의 빈도를 줄인다.

 

여기서 Fill Factor 란?

인덱스 페이지에 데이터가 삽입될 때 얼마나 채울지 비율을 지정하는 설정이다.
값은 0~100 사이로 지정할 수 있으며, 100 은 페이지를 완전히 채운다는 의미이다.
일반적으로 기본값은 0 이다.
(*Fill Factor 0: 인덱스 페이지를 가능한 최대로 채우려고 지시하나, SQL Server 내부적으로 페이지를 최적화하기 위해 약간의 여유 공간을 남길 수 있다.)

인덱스 생성 시 Fill Factor 를 낮게 설정하면 왜 페이지 스플릿이 줄어드는지 확인해보자.

하나의 인덱스 페이지에는 8개의 데이터가 들어갈 수 있다고 가정해보자.

-- Fill Factor 100% (사용 공간 100, 여유 공간 0)
+--------------------------------+
|        Index Page (100%)       |
|--------------------------------|
|  1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
+--------------------------------+
| No Free Space                  |
+--------------------------------+

Fill Factor 100% 의 경우에는 위와 같이 8개의 데이터가 들어가 있을 것이다.

반면, Fill Factor 70% 의 경우에는 아래처럼 5개의 데이터까지밖에 못들어간다. (70% 사용)
그래서 두번째 인덱스 페이지가 생성되고, 여기에 남은 6,7,8 데이터가 들어가게 된다.

-- Fill Factor 70% (사용 공간:70, 여유 공간: 30)
첫 번째 인덱스 페이지:
+---------------------------+
|    Index Page 1 (70%)     |
|---------------------------|
|  1 | 2 | 3 | 4 | 5        |
+---------------------------+
| 30% Free Space            |
+---------------------------+

두 번째 인덱스 페이지:
+---------------------------+
|    Index Page 2 (70%)     |
|---------------------------|
|  6 | 7 | 8                |
+---------------------------+
| 30% Free Space            |
+---------------------------+

 

이 상태에서 새로운 9번 데이터가 들어온다고 하자.
그러면 Fill Factor 100% / 70% 각각 어떻게 될까?

Fill Factor 100% 는 아래와 같이 인덱스 스플릿이 발생할 것이다.

-- Fill Factor 100% (Index Split 발생)
+--------------------------+      +--------------------------+
|       Index Page 1       |      |       Index Page 2       |
|--------------------------|      |--------------------------|
| 1 | 2 | 3 | 4 | 5        |      | 6 | 7 | 8 | 9            |
+--------------------------+      +--------------------------+


반면, Fill Factor 70% 는 여유 공간이 사용되어 인덱스 스플릿이 발생하지 않을 것이다.

-- Fill Factor 70% (Index Split 발생하지 않고, Index Page2 의 여유공간에 9번 데이터 추가됨)
+--------------------------+      +--------------------------+
|       Index Page 1       |      |       Index Page 2       |
|--------------------------|      |--------------------------|
| 1 | 2 | 3 | 4 | 5        |      | 6 | 7 | 8 | 9            |
+--------------------------+      +--------------------------+

 

이처럼 Fill Factor 설정에 따라 초기 인덱스 페이지의 수와 스플릿 발생 여부가 달라지게된다.
Fill Factor 를 낮게 설정하면 초기 인덱스 페이지의 수는 늘어나지만 인덱스 스플릿 현상을 줄일 수 있게 된다.

하지만, Fill Factor 가 낮아 데이터가 여러 페이지에 분산이 되게 되는데, 그러면 읽기 성능에 영향을 미칠 수 있다.
고로 시스템 사용에 맞게 Fill Factor 를 조정하는 것이 중요하다.

  높은 Fill Factor (90~100%) 낮은 Fill Factor (70~80%)
장점 초기 디스크 공간 효율성
 - 처음부터 페이지를 가득 채우므로 디스크 공간을 효율적으로 사용하게 된다.
인덱스 스플릿 감소
 - 인덱스 페이지에 여유 공간이 있어 삽입되는 데이터에 대해 스플릿 빈도가 줄어든다.
단점 인덱스 스플릿 증가
 - 페이지가 가득 찬 상태에서 새로운 데이터가 삽입될 때마다 인덱 스플릿이 발생하여 삽입 성능이 저하되며, 디스크 I/O 사용량이 증가하게 된다.
초기 디스크 공간 사용 증가
 - 데이터가 분산이 되어 여러 페이지를 사용하기 때문에 디스크 공간을 더 많이 사용하게 된다.

읽기 성능 저하
 - 데이터가 여러 페이지에 분산되어 읽기 성능에 약간의 영향을 미칠 수 있다. (크게 문제가될 정도는 아님)
사용 권장 환경 디스크 공간이 제한되며,
읽기 작업이 주로 발생하는 환경
DML 작업이 빈번한 환경

 

2. 주기적인 인덱스 리빌드(Rebuild) 및 재구성(Reorganize)

주기적으로 인덱스 리빌드 및 인덱스 재구성 작업을 통하여 단편화를 줄인다.

인덱스 리빌드(Index Rebuild)
인덱스 리빌드는 기존 인덱스를 완전히 다시 만드는 과정이다. 이 과정에서 인덱스가 새로운 페이지에 정렬되고, 단편화가 완전히 제거된다. 다만, 이로 인한 디스크I/O 가 발생하며 작업시간이 다소 오래 걸리며, 테이블 전체 잠금이 발생한다. 인덱스 단편화가 30% 이상 발생 시 사용하며 점검 작업 중 하는 것을 추천한다.

인덱스 재구성(Index Reorganize)
인덱스 재구성은 기존 인덱스 페이지를 재정렬하여 단편화를 줄이는 과정이다. 인덱스를 다시 만들지 않고, 현재 페이지를 정리한다. 인덱스 리빌드에 비해 디스크I/O 가 적고 작업 시간이 덜 걸리며, 페이지 수준 잠금이 발생한다. 일부 단편화가 남을 수 있다. 인덱스 단편화가 10~30% 일때 사용하며 라이브 환경에서 사용이 가능하다.

 

3. 적절한 인덱스 설계

  • 순차적인 키 사용
    • 순차적인 키를 사용하는 인덱스는 데이터가 순서대로 삽입이 되어 인덱스 스플릿이 덜 발생한다.
    • 예를 들어, IDENTITY 또는 AUTO_INCREMENT 컬럼과 같이 순차적으로 증가하는 컬럼이 인덱스의 키로 적합하다.
  • 변경이 적은 컬럼 인덱싱
    • 자주 변경되지 않는 컬럼을 인덱스로 사용하면 변동 사항이 없어 인덱스 스플릿을 줄일 수 있다.

 

결론

이와 같이 인덱스 스플릿은 디스크I/O 를 증가시키고, 인덱스 트리를 재구성하는데 추가적인 오버헤드를 발생시킨다.
이를 최소화하기 위해 Fill Factor 설정, 인덱스 재구성 및 적절한 인덱스 설계를 통해 인덱스 스플릿이 발생하지 않도록 최적화하여야 한다.

 

 

반응형