[DB] 인덱스(Index) 개념

·2025년 1월 14일

데이터베이스

목록 보기
16/22
post-thumbnail

I/O

  • I/O(Input/Output)는 컴퓨터 시스템에서 데이터를 입력받고 출력하는 작업을 의미
  • I/O 과정은 시스템 성능에 중요하며, 대량 데이터를 처리하는 애플리케이션에는 효율적인 I/O 관리가 필요

I/O 종류

순차 I/O

  • 데이터를 디스크의 연속된 위치에서 순서대로 읽고 쓰는 방식
  • 디스크의 헤드 이동 없이 연속적인 접근이 가능해 처리량(Throughput) 높음
  • 대규모 데이터 읽기/쓰기 작업에 적합

예시:

  • 데이터베이스에서 풀 테이블 스캔(Full Table Scan)
  • 테이블의 모든 데이터를 조회하는 상황

랜덤 I/O

  • 데이터가 디스크의 임의의 위치에 분산되어 있어, 여러 위치를 이동하며 데이터를 읽고 쓰는 방식
  • 디스크의 헤드 이동(Seek) 시간이 많아 오버헤드 발생
  • 작은 데이터를 빈번히 처리할 때 주로 발생

예시:

  • WHERE(조건)이 포함된 쿼리를 통해 조회 및 수정 및 삭제하는 상황
  • 인덱스 레인지 스캔

순차 I/O의 경우 한 번의 시스템 호출로 여러 데이터를 기록하며, 반면 랜덤 I/O는 각 데이터마다 별도의 시스템 호출이 필요하므로 효율이 떨어짐
따라서, 성능 최적화를 위해 랜덤 I/O를 최소화하고, 즉, 쿼리를 처리시 꼭 필요한 데이터만 읽도록 쿼리를 개선 하는 것을 의미


인덱스

인덱스(Index)란?

  • 데이터를 빠르게 찾기 위해 특정 컬럼을 기준으로 미리 정렬해놓은 표
  • 책의 목차처럼, 원하는 데이터를 바로 찾아갈 수 있도록 위치 정보를 제공

인덱스 장단점

장점

  • 데이터 조회 속도 향상
  • 테이블 전체를 풀스캔(Full Table Scan)하지 않고, 원하는 데이터를 빠르게 찾을 수 있음
  • 인덱스를 사용하면 랜덤 I/O가 발생하지만, 필요한 데이터만 읽기 때문에 전체 테이블을 읽는 것보다 I/O 작업량이 줄어듬

단점

  • 추가적인 저장 공간 필요
  • 데이터 삽입, 수정, 삭제 시 추가적인 연산 필요 (정렬을 유지해야하기 때문에 추가 연산)
    • 삽입: 새로운 데이터에 대한 인덱스를 추가
    • 삭제: 삭제하는 데이터의 인덱스를 사용하지 않는다는 작업 수행
    • 수정: 기존 인덱스를 사용하지 않음 처리하고 갱신된 데이터의 인덱스 추가

인덱스 설정 기준

  • WHERE, JOIN, GROUB BY, ORDER BY 조건에 자주 사용되는 컬럼
  • INSERT, UPDATE, DELETE 연산이 자주 발생하지 않는 컬럼
  • 카디널리티가 높고 선택도가 낮은 컬럼
    • 카디널리티가 높다는 것은 한 컬럼이 가지는 값의 중복도가 낮다는 것을 의미 (해당 컬럼 값이 다양함)
      • 주민등록번호 (높음)
      • 성별(M or W) (낮음)
    • 선택도가 낮다는 것은 한 컬럼으로 조건을 검색했을 때, 결과 집합이 작다는 뜻
  • 자주 조합되어 사용되는 컬럼들은 결합인덱스로 사용
    • 첫 번째 컬럼부터 조건에 사용되어야 인덱스를 제대로 활용 가능
  • 규모가 작지 않는 테이블

카디널리티가 낮은 컬럼에 인덱스를 걸면, 더 많은 데이터를 랜덤 I/O를 해야하기 때문에, 오히려 테이블 풀스캔(순차 I/O)으로 데이터를 찾는것이 더 좋을 수 있음

인덱스 구조

  • 일반적으로 Hash, B-Tree, B+Tree 등으로 사용해 구현됨

1. Hash

  • Key-Value 형태의 자료구조
  • 주로 = 조건의 검색에 최적화되어 있으며 O(1) 시간 복잡도를 가짐
  • 실제 키 값과와 관계없이 해시 값을 저장하기 때문에 인덱스 크기가 작음
  • 정렬되어 있지 않기때문에 범위 검색에는 적합하지 않음
  • RDBMS에서는 잘 사용하지 않고 제한적으로 사용됨

2. B-Tree

  • 이진 탐색 트리는 탐색 시간 복잡도가 O(logN)를 가지지만, 트리가 편향될 경우 최악의 시간복잡도는 O(N)를 가짐
  • B-Tree는 Balcened Tree(균형 트리)를 기반으로, 삽입과 삭제 작업 후에도 트리가 자동으로 균형을 유지하여 시간 복잡도가 O(logN) 으로 보장
  • 모든 리프 노드는 같은 레벨에 위치하여 트리가 항상 균형을 유지
  • 자식 노드를 2개이상 가질 수 있음
  • 키는 정렬된 상태로 저장되어, 범위 검색에 효율적

한계

  • 데이터를 내부 노드(루트 노드 및 리프 노드가 아닌 노드)와 리프 노드(자식 노드가 없는 노드)에 분산 저장하므로, 특정 키를 검색하거나 탐색 시 디스크 접근이 더 자주 발생
  • 데이터를 내부 노드와 리프 노드에 분산 저장하므로, 범위 검색이나 순차적 데이터 접근 시 여러 노드를 반복적으로 탐색해야 하여 비효율적

3. B+Tree

  • B-Tree의 한계를 개선하고 확장한 자료구조로, 특히 범위 검색과 순차적 데이터 접근에서 효율적
  • 모든 데이터는 리프 노드에서만 저장되고, 내부노드는 탐색을 위한 키와 포인터만 포함, 이때 키가 중복 될 수 있음
  • 리프 노드 간 연결 리스트 형태로 연결되어 순차적 데이터 접근이 효율적
  • 리프노드를 제외하고 데이터를 저장하지 않기 때문에 메모리를 더 확보할 수 있기에 하나의 노드에 더 많은 포인터를 가질 수 있음
    => 이로 인해 트리의 높이가 더 낮아지므로 검색 속도를 높임
  • 검색은 B-Tree와 동일하지만, 삽입 및 삭제는 항상 리프노드에서 이루어짐
  • B-Tree의 경우 최상의 경우 특정 키를 루트노드에서 찾을 수 있지만, B+Tree는 특정 키에 접근하기 위해 반드시 리프노드까지 가야하는 단점이 있음


B Tree 계열을 DB 인덱스로 왜 사용할까?

  • DB는 기본적으로 Secondary storage(SSD or HDD)에 저장됨

Secondary storage(SSD or HDD) 특징

  • 데이터를 처리하는 속도가 가장 느림
    • 속도 비교: RAM < SSD < HDD
    • DB 조회 시 Secondary Storage 접근 최소화가 성능에 매우 중요
  • 데이터를 저장하는 용량이 가장 큼
  • block 단위로 데이터를 읽고 씀
    • block: file system이 데이터를 읽고 쓰는 논리적인 단위 (4KB, 8Kb, 16KB...)
    • 이는 불필요한 데이터까지 읽어올 가능성이 있음

B-Tree 인덱스의 장점 (Self-balancing Binary Search Tree와 비교)

  • 여러 개의 자식 노드를 가질 수 있음
    • 트리의 깊이가 낮아져 Secondary Storage 접근이 줄어듦
  • 하나의 노드에 여러 개의 데이터를 저장할 수 있음
    • 블록 단위로 데이터를 읽고 쓰는 Secondary Storage 특성에 최적화
    • 저장 공간을 효율적으로 활용하고, 한 번의 I/O로 더 많은 데이터를 처리 가능

인덱스 종류

1. 클러스터 인덱스(Clustered Index)

  • 테이블 자체가 정렬된 인덱스 구조로 저장됨
  • 주로 PK(Primary Key)로 생성되며, 하나의 테이블에는 하나의 클러스터 인덱스만 생성 가능
  • 데이터가 정렬되어 저장되므로, 범위 검색, 순차적 데이터 접근에 유용
  • 데이터 삽입/수정/삭제 시 물리적 정렬을 유지해야 하므로 오버헤드가 발생

예시: 사용자 테이블에서 ID 컬럼을 기준으로 데이터를 정렬

2. 논 클러스터 인덱스(Non Clustered Index)

  • 테이블의 물리적 데이터 순서와 독립적으로 생성되는 인덱스
  • 인덱스에는 키 값과 해당 데이터의 포인터가 저장되며, 실제 데이터는 테이블에 별도로 저장됨
  • 하나의 테이블에 여러개 논 클러스터 인덱스 생성 가능
  • 실제 데이터 페이지는 정렬되지 않으므로, 삽입, 삭제, 수정연산이 빠르나 검색연산이 클러스터 인덱스보다 느림

예시: 사용자 테이블의 email 컬럼에 대해 검색 성능을 최적화하는 논 클러스터 인덱스

3. 유니크 인덱스(Unique Index)

  • 인덱스에 저장된 값이 중복되지 않도록 보장하는 인덱스
  • Primary Key와 Unique Key 제약 조건에 의해 자동으로 생성
  • 삽입, 수정 시 중복 확인을 위한 오버헤드 발생

예시: email 컬럼에 유니크 인덱스를 생성하여 중복 이메일 주소 삽입 방지

4. 결합 인덱스(Composite Index)

  • 여러 컬럼을 결합하여 하나의 인덱스를 생성
  • 인덱스의 컬럼 순서가 쿼리의 조건 순서와 맞아야 제대로 활용 가능

예시: (A, B)로 구성된 결합 인덱스는 WHERE A = 1 AND B = 2 조건에서는 제대로 활용되지만, WHERE B = 2 조건에서는 인덱스를 충분히 활용하지 못할 수 있음. 단, WHERE A = 1 조건만 사용하는 경우에는 A 컬럼에 대해서는 인덱스를 활용할 수 있음

5. 비트맵 인덱스 (Bitmap Index)

  • 컬럼의 값을 비트맵으로 변환하여 저장
  • 카디널리티가 낮은 데이터(값의 종류가 적음)에 적합
  • 논리 연산(AND, OR)에 효율
  • 저장 공간이 적고 읽기 작업에 효율
  • 삽입/수정/삭제 시 갱신 비용이 큼

예시: 성별(M/F) 또는 상태코드(0/1)와 같은 값의 종류가 적은 데이터에 적용

6. 전문 검색 인덱스 (Full-Text Index)

  • 텍스트 데이터 검색에 최적화된 인덱스
  • 역색인(Inverted Index) 방식
    • 각 단어를 키로, 해당 단어가 포함된 문서의 목록을 값으로 저장
  • 자연어 검색, 부울 검색(AND, OR, NOT) 등 고급 검색 기능 지원
  • 텍스트 데이터에서 키워드 검색, 유사 검색, 단어 간 거리 조건을 효율적으로 처리

예시: 제품 설명에서 키워드 기반 검색

7. 커버링 인덱스 (Covering Index)

  • 쿼리에서 필요한 모든 데이터를 인덱스만으로 처리할 수 있는 인덱스
  • 테이블의 데이터 페이지에 접근하지 않고도 인덱스만으로 결과를 반환할 수있어, 디스크 I/O를 최소화

0개의 댓글