복합 인덱스를 만들 때 컬럼을 아무 순서로나 넣으면 인덱스가 있어도 안 타는 일이 생깁니다. (a, b, c)와 (c, b, a)는 완전히 다른 인덱스입니다. 순서를 정하는 원칙을 알면 인덱스를 추가하기 전에 효과를 예측할 수 있습니다.
선두 컬럼 규칙
복합 인덱스는 왼쪽 컬럼부터 차례대로만 사용할 수 있습니다. (user_id, status, created_at) 인덱스로 탈 수 있는 조건:
| WHERE 조건 | 인덱스 사용 |
|---|---|
user_id=42 | O (선두만 써도 됨) |
user_id=42 AND status='paid' | O (앞 2개) |
status='paid' | X (선두 건너뜀) |
status='paid' AND created_at>... | X (선두 없음) |
status만으로 조회하면 인덱스를 못 탑니다. 선두 컬럼인 user_id가 조건에 없으면 그 뒤는 무의미합니다.
등호 먼저, 범위는 마지막
컬럼 순서의 핵심 규칙입니다. 등호(=) 조건 컬럼을 앞에, 범위(>, <, BETWEEN) 컬럼을 뒤에 둡니다. 범위 조건이 걸린 컬럼 이후의 컬럼은 인덱스 정렬을 더 못 씁니다.
SQL
-- 조회: WHERE user_id=42 AND created_at >= '2026-12-01' AND status='paid'
-- 나쁨: (user_id, created_at, status) — created_at 범위 뒤의 status는 못 탐
-- 좋음: (user_id, status, created_at) — 등호 둘 먼저, 범위 마지막
created_at을 범위로 쓰면서 중간에 두면, 그 뒤 status는 인덱스로 좁히지 못하고 걸러내기만 합니다.
카디널리티로 순서 다듬기
카디널리티(고유값 수)가 높은 컬럼을 앞에 두면 더 적은 행으로 빨리 좁혀집니다. 단, 위의 "선두 컬럼/등호 우선" 규칙이 먼저고, 그 안에서 카디널리티를 따집니다.
SQL
SELECT
COUNT(DISTINCT user_id) AS u, -- 높음 (수십만)
COUNT(DISTINCT status) AS s -- 낮음 (3~4개)
FROM orders;
status처럼 값이 몇 개뿐인 컬럼을 단독·선두로 인덱싱하면 절반 이상을 읽게 돼 효과가 작습니다.
커버링 인덱스로 한 단계 더
조회하는 컬럼까지 인덱스에 다 들어 있으면 테이블 본체를 안 읽고 인덱스만으로 끝납니다. EXPLAIN Extra에 Using index가 뜹니다.
SQL
-- SELECT status, created_at WHERE user_id=42
-- 인덱스 (user_id, status, created_at) 면 테이블 접근 없이 해결
설계 체크리스트
SQL
EXPLAIN SELECT ...; -- key가 의도한 인덱스인가, Extra=Using index인가
SHOW INDEX FROM orders; -- Cardinality 컬럼 확인
-- WHERE의 등호 컬럼이 선두에 모여 있는가
-- 범위 조건 컬럼이 맨 뒤인가
-- ORDER BY 컬럼이 인덱스 순서와 맞는가
인덱스 순서를 바꿔가며 EXPLAIN으로 실행계획 변화를 직접 확인하는 실습은 데이터베이스 트랙에서 회원가입 없이 무료로 할 수 있습니다.