DB/데이터 관리

인덱스 파편화와 해결 전략

dddzr 2026. 4. 8. 15:34

📌 UUID PK 사용 시 필수 고려사항: 인덱스 파편화와 해결 전략

 

이번에 메뉴테이블의 PK를 시스템 확장성을 위해 Sequence 대신 UUID(Universally Unique Identifier)로 변경하는 작업을 진행했다.

하지만 무작위 UUID는 DB 인덱스 성능을 저하 시킬 수 있기에 인덱스 파편화는 UUID PK 채택 시 고려사항 중 하나다!!

인덱스 관리가 필요한 이유와 실무적인 해결책을 정리한다.


📌1. 인덱스 파편화(Index Fragmentation)의 정의

DB 인덱스는 '번호 순서대로 정렬된 백과사전'과 같다. 데이터를 빠르게 찾기 위해 내부적으로 일정한 정렬 상태를 유지해야 한다.

  • Sequence(1, 2, 3...) 방식: 새 데이터가 들어오면 기존 인덱스 페이지의 맨 뒤 빈 공간에 차곡차곡 쌓인다. 물리적 저장 순서와 논리적 순서가 일치하여 매우 효율적이다.
  • UUID(Random) 방식: 새 값의 ID가 a1..., f5... 처럼 무작위다. 이미 데이터가 꽉 찬 사전 중간 어딘가에 억지로 끼워 넣어야 하는 상황이 발생한다.
  • 페이지 분할(Page Split): 중간에 자리가 없으면 DB는 기존 데이터를 옆으로 밀거나, 공간 확보를 위해 페이지를 반으로 쪼개는(Page Split) 작업을 수행한다.

이 과정이 반복되면 인덱스 페이지 내부에 사용하지 않는 빈 공간이 생기고 데이터가 물리적으로 흩어지게 된다. 이를 **'인덱스 파편화'**라고 부른다!!


📌2. 인덱스 관리가 필요한 이유 (정렬, 검색 성능)

비즈니스 로직에서 ORDER BY menu_id를 호출하지 않더라도, 단건 검색(WHERE menu_id = '...') 성능에 직접적인 타격을 준다.

 이유 1: 검색 효율(Select) 저하

파편화가 심해지면 DB가 읽어야 할 '페이지' 수가 늘어난다.

  • 정상 상태: 데이터 100개가 페이지 1장에 모여 있음 → 디스크 I/O 1회 발생.
  • 파편화 상태: 데이터 100개가 쪼개진 페이지 10장에 흩어져 있음 → 디스크 I/O 10회 발생.
    👉 결과적으로 동일한 데이터를 조회하더라도 서버 자원을 더 많이 소모하고 응답 속도가 느려진다.

 이유 2: 삽입 성능(Insert) 저하

데이터를 저장할 때마다 최적의 위치를 계산하고 페이지를 쪼개는 추가 연산이 발생한다. 데이터가 쌓일수록 저장 속도가 점진적으로 저하되는 원인이 된다.


📌3. 실무적인 DB 설계 및 대응 전략

Oracle 등 주요 DBMS 환경에서 이를 방어하기 위한 3가지 전략이다.

✅ 전략 1: 일반적인 Heap 테이블 방식

데이터는 빈 공간에 자유롭게 쌓고(Heap), 인덱스만 별도로 정렬하여 관리하는 가장 보편적인 방식이다.

  • 정렬, 검색의 기준이 되는 데이터로 보조 인덱스를 생성한다.
  • 만약 정렬/검색이 전혀 이루어 지지 않는다면 보조 인덱스 생성은 생략.
-- 테이블 생성 (PK는 UUID)
CREATE TABLE MENU (
    MENU_ID      VARCHAR2(32) NOT NULL,
    MENU_NM      VARCHAR2(100),
    SORT_NUMBER  NUMBER(5), -- 비즈니스 정렬용 컬럼
    CREATED_AT   DATE DEFAULT SYSDATE,
    CONSTRAINT PK_MENU PRIMARY KEY (MENU_ID)
);

-- 실제 조회가 빈번한 SORT_NUMBER와 생성일자에 보조 인덱스 생성
CREATE INDEX IX_MENU_SORT ON MENU (SORT_NUMBER, CREATED_AT);

-- 사용 여부와 메뉴명을 묶은 인덱스 
CREATE INDEX IX_MENU_NAME_SEARCH ON MENU (USE_YN, MENU_NM);

✅ 전략 2: 인덱스 리빌드 (운영 단계)

랜덤 UUID를 사용 중이라면, 정기적으로 인덱스를 재구성하여 빈 공간을 제거해야 한다.

  • 메뉴 ID(PK)로 검색할 때 성능(속도)를 위해 필요하다.
  • 메뉴 ID(PK)로 검색하는 로직이 아예 없고, 오직 메뉴명(MENU_NM)으로만 검색한다면 PK 인덱스 리빌드는 신경 쓰지 않아도 된다.
  • 보통 트래픽이 적은 시간대에 배치 작업으로 수행하여 인덱스 밀도를 높인다.
-- 서비스 중단 없이 인덱스 재구성 (Oracle 기준)
ALTER INDEX PK_MENU REBUILD ONLINE;

✅ 전략 3: Sequential UUID (설계 단계 - 권장)

가장 근본적인 해결책이다. Java 등 애플리케이션 레이어에서 UUID v7이나 Sequential UUID 라이브러리를 사용하여 식별자를 생성한다.

  • 특징: UUID의 유일성은 유지하되, 앞부분에 타임스탬프를 포함하여 생성 순서대로 정렬되는 성질을 갖는다.
  • 장점: DB 입장에서는 데이터가 순차적으로 들어오는 것으로 인식하여 페이지 분할을 방지하고 삽입 성능을 극대화할 수 있다.

💡 요약 및 결론

  1. 현상: 랜덤 UUID는 인덱스 중간에 삽입되며 '페이지 분할'과 '파편화'를 유발한다.
  2. 결과: 직접적인 정렬 로직이 없더라도 조회 성능 저하와 디스크 자원 낭비로 이어진다.
  3. 결론: 신규 설계 시 Sequential UUID 도입을 최우선으로 검토하고, 운영 중인 시스템은 Index Rebuild를 통해 성능을 유지해야 한다.

 

'DB > 데이터 관리' 카테고리의 다른 글

Elasticsearch > analyzer  (0) 2026.01.25
개인 식별 정보 암호화 방법  (0) 2026.01.25
CTE(Common Table Expression)란?  (0) 2025.11.29
Elasticsearch란?  (0) 2025.04.10
JDBC / SQL Mapper / ORM (JPA, Hibernate, MyBatis)  (0) 2024.09.25