데이터베이스

복합 인덱스 설계의 오해와 실체: 선택도가 아니라 연산자가 기준이다

Stitchhhh 2026. 7. 2. 11:26

인덱스를 만들 때 "선택도(Selectivity)가 높고 데이터가 잘 분산된 칼럼을 앞에 두라"는 조언이 많지만, 이는 데이터베이스 내부 동작 원리를 고려하지 않은 오해에 가깝습니다. 복합 인덱스 칼럼 순서를 결정하는 진짜 기준을 정리합니다.

1. 모든 조건이 등호(=)일 때: 순서는 상관없다

두 칼럼을 모두 등호 조건으로 조회하는 경우, 칼럼 순서가 바뀌어도 성능 차이는 없습니다.

SELECT * FROM employees 
WHERE employee_id = 123 AND subsidiary_id = 20;
  • 이유: B-Tree 인덱스는 왼쪽 칼럼부터 순서대로 다단 정렬됩니다. 두 조건 모두 명확한 값(=)을 지정했다면, 어느 칼럼이 앞에 오든 목적지 데이터로 향하는 탐색 경로와 비용은 동일합니다.
  • 진짜 기준: 이때 순서를 결정하는 것은 선택도가 아니라 "어떤 칼럼이 단독으로 자주 검색되는가"라는 쿼리 패턴(워크로드)입니다.

2. 인덱스 매칭의 핵심: Access vs Filter

인덱스 순서가 성능을 가르는 진짜 경계선은 쿼리에 범위 조건(, <, BETWEEN, LIKE)이 포함될 때입니다.

  • Access Predicate: 스캔해야 할 데이터의 물리적인 시작점과 끝점을 정확히 짚어주는 조건입니다.
  • Filter Predicate: 시작점과 끝점이 정해진 후, 그 구역을 처음부터 끝까지 스캔하면서 조건에 맞지 않는 데이터를 하나씩 걸러내는 조건입니다. (물리적 I/O 낭비 발생)

3. 범위 조건 뒤에서 정렬이 깨지는 이유

복합 인덱스는 선행 칼럼의 값이 '정확히 같을 때만' 그 다음 칼럼이 정렬을 유지하는 계층형 정렬 방식입니다.

인덱스가 (나이, 점수) 순서로 정렬되어 있을 때, WHERE 나이 BETWEEN 20 AND 30 AND 점수 = 70 쿼리를 던지면 엔진은 나이가 20~30인 구역을 박스로 묶어 바라봅니다.

[DB 엔진이 스캔해야 하는 범위]
나이 | 점수 (두 번째 칼럼)
-------------------------
20  | 30
20  | 80
30  | 40
30  | 70

이 안에서 점수 칼럼만 보면 30 -> 80 -> 40 -> 70으로 정렬이 완전히 깨져 있습니다. 줄이 깨졌기 때문에 엔진은 점수 = 70인 위치로 순간이동(Access)하지 못하고, 이 범위를 처음부터 끝까지 읽으며 하나씩 검사하는 Filter 조건으로 처리하게 됩니다.

4. 인덱스 매칭 판별 규칙

엔진은 쿼리문의 글자 타이핑 순서와 무관하게, 이미 생성된 인덱스의 칼럼 배치 순서(왼쪽 $\rightarrow$ 오른쪽)를 따라 조건을 조립하며 아래 규칙대로 판단합니다.

조건 종류 및 위치 판별 결과 내부 동작
범위 조건을 만나기 전의 등호(=) 조건 Access 정렬을 유지하며 대상을 좁힘
인덱스 순서상 가장 처음 만난 범위 조건 Access 스캔할 구역의 시작점/끝점을 지정함
첫 범위 조건보다 오른쪽에 배치된 모든 칼럼 Filter 앞 칼럼 때문에 인덱스 내 정렬이 깨져 전수조사 수행

요약

선택도라는 수치보다 쿼리에 사용된 연산자가 등호냐 범위냐가 인덱스 성능을 지배합니다.

  1. 등호(=) 조건으로 쓰이는 칼럼을 앞쪽에 배치합니다.
  2. 범위(>, <, BETWEEN, LIKE) 조건으로 쓰이는 칼럼은 뒤쪽에 배치합니다.
  3. 그 외에는 시스템 전체에서 어떤 칼럼이 단독으로 자주 조회되는지 쿼리 패턴을 보고 정합니다.