데이터베이스/RDBMS (관계형 데이터베이스)

[DB] Index: 중요성, 종류, 최적화 방법

ioh'sDeveloper 2025. 1. 5. 17:03

데이터베이스 인덱스: 중요성, 종류, 그리고 최적화 방법

데이터베이스 인덱스란?

데이터베이스 인덱스는 데이터 검색 속도를 향상시키는 데이터 구조입니다. 인덱스는 데이터베이스가 특정 행을 빠르게 찾을 수 있도록 도와주는 지도 역할을 합니다. 하지만 인덱스를 사용하면 저장 공간이 더 필요하고, 쓰기 작업이 느려지는 단점이 있습니다.


인덱스가 중요한 이유

인덱스는 관계형 데이터베이스에서 쿼리 실행 시간을 크게 줄여줍니다. 인덱스가 없으면 데이터베이스는 전체 테이블 스캔을 수행하여 각 행을 검사해야 합니다. 이 경우 시간 복잡도는 **O(N)**입니다. 하지만 인덱스를 사용하면 **O(log N)**의 시간 복잡도로 훨씬 빠르게 데이터를 검색할 수 있습니다.

예를 들어, customer 테이블에서 아래와 같은 MySQL 쿼리가 있다고 가정해봅시다:

SELECT * FROM customer WHERE first_name = 'Minsoo';

이 테이블에 100만 개의 행이 있고 first_name 컬럼에 인덱스가 없다면 데이터베이스는 모든 행을 검사해야 합니다. 하지만 first_name 컬럼에 인덱스를 설정하면 데이터베이스는 해당 인덱스를 통해 일치하는 행을 빠르게 찾을 수 있습니다.


MySQL에서 인덱스 생성 방법

인덱스는 기존 테이블에 추가할 수도 있고, 테이블을 생성할 때 지정할 수도 있습니다.

기존 테이블에 인덱스 추가하기

CREATE INDEX customer_first_name_idx ON customer (first_name);

고유 인덱스 생성하기

컬럼 조합이 고유해야 하는 경우(예: 스포츠 선수 테이블에서 팀과 등번호 조합) **고유 인덱스(Unique Index)**를 생성할 수 있습니다:

CREATE UNIQUE INDEX team_id_backnumber_idx ON player (team_id, backnumber);

이 인덱스는 같은 팀에서 동일한 등번호가 중복될 수 없도록 보장합니다.


인덱스의 종류

  1. B-트리 인덱스 (MySQL 기본값)
  2. 해시 인덱스(Hash Index)
  3. 전체 텍스트 인덱스(Full-Text Index)
  4. 공간 인덱스(Spatial Index)

대부분의 경우 B-트리 인덱스가 범위 검색과 동등 검색을 효율적으로 지원하기 때문에 가장 널리 사용됩니다.


인덱스의 작동 방식: B-트리 구조

B-트리 인덱스는 MySQL에서 가장 일반적으로 사용되는 인덱스 유형입니다. 이는 데이터를 균형 잡힌 트리 구조로 구성하여 데이터베이스가 트리를 빠르게 탐색할 수 있도록 합니다.

예시:

인덱스 테이블:
+-----------+-----------+
| 인덱스 키  | 행 ID     |
+-----------+-----------+
| Minsoo    | 1001      |
| Jisoo     | 1002      |
+-----------+-----------+

데이터베이스는 전체 테이블을 스캔하는 대신 인덱스를 검색하여 검색 범위를 크게 줄일 수 있습니다.


커버링 인덱스(Covering Index)

커버링 인덱스는 쿼리가 필요한 모든 컬럼을 포함하는 인덱스입니다. 이 경우 데이터베이스는 테이블에 접근하지 않고 인덱스만으로 쿼리를 처리할 수 있습니다.

예시:

SELECT first_name, last_name FROM customer WHERE first_name = 'Minsoo';

(first_name, last_name)에 인덱스가 있다면, 쿼리는 테이블을 조회하지 않고 인덱스만으로 처리할 수 있습니다.


해시 인덱스(Hash Index)

해시 인덱스는 해시 테이블을 사용하여 값을 위치에 매핑합니다. 이는 O(1) 시간 복잡도로 동등 검색을 수행할 수 있지만 몇 가지 한계가 있습니다:

  • 동등 비교 쿼리만 지원합니다.
  • 범위 검색을 지원하지 않습니다.
  • 해시 충돌이 발생할 경우 **재해싱(Rehashing)**이 필요합니다.

이러한 제한 사항으로 인해 대부분의 경우 B-트리 인덱스가 더 적합합니다.


인덱스 사용 예시

player 테이블을 고려해봅시다:

CREATE TABLE player (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    team_id INT,
    backnumber INT
);

예시 1: 이름으로 검색

SELECT * FROM player WHERE name = 'Sonny';

해결 방법:

CREATE INDEX player_name_idx ON player (name);

예시 2: 팀과 등번호로 검색

SELECT * FROM player WHERE team_id = 105 AND backnumber = 7;

해결 방법:

CREATE UNIQUE INDEX team_id_backnumber_idx ON player (team_id, backnumber);

인덱스 사용 시 베스트 프랙티스

  1. WHERE, JOIN, ORDER BY, GROUP BY 절에 자주 사용되는 컬럼에 인덱스를 생성합니다.
  2. 불필요한 인덱스를 생성하지 않습니다. 인덱스가 많으면 쓰기 작업(INSERT, UPDATE, DELETE)이 느려집니다.
  3. 복합 인덱스(Composite Index)를 활용합니다. 여러 컬럼을 동시에 필터링하는 쿼리에 유용합니다.
  4. EXPLAIN 명령어로 쿼리 실행 계획을 분석합니다.
  5. 사용하지 않는 인덱스를 제거합니다.

인덱스의 단점

  • 저장 공간 사용 증가: 각 인덱스는 추가 디스크 공간을 차지합니다.
  • 쓰기 작업이 느려짐: 행을 삽입, 업데이트, 삭제할 때마다 관련된 모든 인덱스를 업데이트해야 합니다.
  • 인덱스 유지 관리 필요: 최적의 성능을 유지하려면 정기적으로 인덱스를 점검해야 합니다.

옵티마이저와 인덱스 선택

MySQL의 쿼리 옵티마이저는 각 쿼리에 대해 가장 적합한 인덱스를 자동으로 선택합니다. 그러나 경우에 따라 서브옵티멀 인덱스를 선택할 수 있습니다. 이때 개발자는 다음과 같은 방법으로 인덱스 사용을 조정할 수 있습니다:

  • 인덱스 힌트를 사용하여 특정 인덱스를 지정합니다.
  • EXPLAIN을 사용하여 쿼리 실행 계획을 분석합니다.

인덱스 힌트 예시:

SELECT * FROM player USE INDEX (player_name_idx) WHERE name = 'Sonny';

요약

인덱스는 데이터베이스 최적화의 핵심 요소입니다. 인덱스를 사용하면 쿼리 성능이 크게 향상되며, 검색 속도가 **O(N)**에서 **O(log N)**로 줄어듭니다. 그러나 인덱스 수와 유형을 신중하게 관리해야 하며, 정기적으로 쿼리 성능과 인덱스 사용 상태를 분석하는 것이 중요합니다.

적절한 인덱스를 이해하고 적용함으로써 대규모 데이터셋에서도 최적의 데이터베이스 성능을 유지할 수 있습니다.