결정: 어떤 인덱스 유형인가?
올바른 인덱스 유형은 쿼리의 접근 패턴(동등, 범위, 텍스트/JSON 검색), 컬럼의 카디널리티, 읽기/쓰기 균형에 따라 달라진다. 잘못된 인덱스는 공간을 낭비하고 쓰기도 느리게 만든다. 이 트리는 쿼리 형태에서 출발해 B-tree, Hash, Bitmap, GIN/GiST, 부분, 커버링 인덱스 중 선택을 안내하며, 복합 인덱스에서는 컬럼 순서가 핵심임을 상기시킨다.
쿼리가 이 컬럼을 어떻게 사용하는가?
접근 패턴은 인덱스 선택에서 가장 결정적인 요소다. 컬럼을 '='로만 비교하는가, 범위/정렬(>, <, BETWEEN, ORDER BY)을 수행하는가, 아니면 전문, JSON 필드, 기하 데이터/배열을 검색하는가? 여기서 시작하며, 요구가 명확해지기 전에는 인덱스 유형을 선택하지 않는다.
- 동등과 범위/정렬 혼합(=, >, <, BETWEEN, ORDER BY)
- 동등(=)만, 범위나 정렬 없음
- 전문, JSON/JSONB 필드, 배열 또는 기하 검색
- 쿼리가 항상 같은 작은 행 부분집합을 대상으로 함(예: WHERE status='active')
컬럼의 카디널리티(고유 값 수)는 어느 정도인가?
범위/정렬이 필요하면 기본값은 B-tree다. 다만 읽기 중심 데이터 웨어하우스에서 고유 값이 매우 적은 컬럼(낮은 카디널리티: 성별, 상태, 예/아니요)에는 Bitmap 인덱스가 더 나을 수 있다. 컬럼에 고유 값이 많은가, 아니면 반복되는 소수의 값인가?
- 높은 카디널리티(고유 값이 많음) 또는 OLTP 워크로드
- 낮은 카디널리티이며 읽기 중심 / 데이터 웨어하우스(DWH)
쿼리가 인덱스에 있는 컬럼만 읽는가?
접근 패턴은 B-tree에 적합하다. 마지막 최적화: 쿼리가 반환하고 필터링하는 모든 컬럼이 인덱스에 있으면 엔진은 테이블을 방문하지 않고 인덱스만으로 응답할 수 있다(index-only / covering scan). 쿼리가 몇 개의 컬럼만 읽는가, 아니면 행의 대부분이 필요한가?
- 예, 몇 개 컬럼만; 테이블 방문 없이 응답 가능
- 아니요, 표준 접근으로 충분함
권장: B-tree(기본)
B-tree는 동등, 범위, 정렬(ORDER BY), LIKE 'abc%' 접두사 매칭, MIN/MAX 등 폭넓은 접근 패턴을 지원하는 균형 트리 구조다. 대부분의 관계형 엔진에서 기본 인덱스 유형이며, 확신이 없을 때 올바른 출발점이다.
권장: Hash 인덱스(동등 조건 전용)
Hash 인덱스는 컬럼 값의 해시를 저장하며 정확한 동등('=') 조회에만 매우 빠르다. 범위, 정렬, 접두사 검색을 지원하지 않으므로 사용 범위가 좁다.
권장: Bitmap 인덱스(낮은 카디널리티 / DWH)
Bitmap 인덱스는 각 고유 값마다 비트 배열을 유지하며, 여러 낮은 카디널리티 조건을 비트 단위 AND/OR로 매우 빠르게 결합한다. 데이터 웨어하우스와 보고처럼 읽기 중심 워크로드에 강하다.
권장: GIN / GiST(텍스트, JSON, 배열, 기하)
PostgreSQL에는 표준 B-tree가 처리할 수 없는 접근 유형을 위한 특수 인덱스 계열이 있다. GIN은 하나의 값 안에 있는 여러 구성 요소(단어, JSONB 키, 배열 요소)를 가리키고, GiST는 기하/범위/최근접 이웃 같은 쿼리에 적합하다.
권장: 부분 / 필터링된 인덱스
부분 인덱스는 테이블 전체가 아니라 조건(WHERE ...)을 만족하는 행만 인덱싱한다. 쿼리가 항상 같은 작은 부분집합을 대상으로 하면 인덱스가 훨씬 작고 빨라지며 쓰기 비용도 줄어든다.
권장: 커버링(INCLUDE) 인덱스
커버링 인덱스는 쿼리에 필요한 모든 컬럼을 포함해 엔진이 테이블(heap)을 전혀 방문하지 않고 인덱스만으로 응답하게 한다(index-only scan). 적은 컬럼을 반환하는 자주 실행되는 쿼리에서 큰 속도 향상을 제공한다.