Foundry
데이터베이스
중급
핵심

복합 인덱스

Leftmost Prefix 규칙, 컬럼 순서 중요

여러 컬럼을 하나로 묶은 인덱스입니다. 선행 컬럼(맨 왼쪽부터 차례로)이 조건에 없으면 인덱스를 타지 못하고, 순서를 정하는 기준은 등가 조건 우선과 선택도(값이 얼마나 잘게 갈리는가)입니다.

복합 인덱스 (Composite Index)

핵심 개념

여러 컬럼을 하나의 인덱스로 묶은 것.

CREATE INDEX idx_user_date
  ON orders (user_id, created_at);

인덱스 구조 (B-tree):
         [user=5, 03-01]
        /                \
[user=3, 02-15]    [user=7, 03-10]
  /         \
[user=1,   [user=3,
 01-20]     03-05]

선행 컬럼 규칙 (Leftmost Prefix)

여러 열로 만든 색인은 왼쪽부터 이어지는 조건에만 쓸 수 있다 색인 순서가 (지역, 상태, 날짜) 일 때 지역과 상태로 찾는다 쓴다 지역만으로 찾는다 쓴다 상태와 날짜로 찾는다 못 쓴다. 왼쪽이 빠졌다 전화번호부를 성 없이 이름만으로 찾을 수 없는 것과 같다 그래서 열 순서가 곧 쓸 수 있는 질의를 정한다 범위 조건은 그 열까지만 쓰이고 그 뒤 열은 걸러내는 데만 쓰인다

복합 인덱스 (A, B, C) 활용 여부:

쿼리 조건인덱스 사용
WHERE A = ?O (A만 사용)
WHERE A = ? AND B = ?O (A, B 사용)
WHERE A = ? AND B = ? AND C = ?O (전체 사용)
WHERE B = ?X (A 없음)
WHERE B = ? AND C = ?X (A 없음)
WHERE A = ? AND C = ?일부 사용 (A 만)

왼쪽부터 연속으로 사용해야 인덱스가 동작한다!

컬럼 순서 설계

규칙: 카디널리티 높은 컬럼 → 앞에

예시: 주문 테이블 검색
  - status: 3종류 (카디널리티 낮음)
  - user_id: 10만 종류 (카디널리티 높음)

권장: INDEX (user_id, status)
  → user_id로 대부분 걸러짐

비권장: INDEX (status, user_id)
  → status로는 33%만 걸러짐

실무 예시: 쇼핑몰 주문 조회

-- 자주 쓰는 쿼리
SELECT * FROM orders
WHERE user_id = 123
  AND status = 'completed'
ORDER BY created_at DESC;

-- 최적 인덱스
CREATE INDEX idx_orders_lookup
  ON orders (user_id, status, created_at);

주의사항

  • 인덱스는 쓰기 성능을 희생하는 대가
  • 불필요한 복합 인덱스는 오히려 독
  • 3-4개 컬럼이 적당 (그 이상은 재고)
면접에서 이렇게 나옵니다

Q.복합 인덱스는 왜 왼쪽 컬럼부터 순서대로 써야 하나요?

복합 인덱스는 앞 컬럼부터 차례로 정렬돼 있어서, 앞 컬럼을 건너뛰면 쓸 수 없습니다.

INDEX (A, B, C) 는 A 로 정렬하고, A 가 같으면 B, 또 같으면 C 로 정렬한다
조건인덱스 사용
A = ?사용
A = ? AND B = ?사용
A = ? AND B = ? AND C = ?사용
B = ?사용 못 함
B = ? AND C = ?사용 못 함
A = ? AND C = ?A 까지만 사용

전화번호부가 성으로 먼저 정렬돼 있으면 이름만으로는 찾을 수 없는 것과 같습니다.

범위 조건도 영향을 줍니다. A = ? AND B > ? AND C = ? 이면 B 까지 쓰고 C 는 정렬이 보장되지 않아 못 씁니다.

흔한 실수: 조건에 쓰인 컬럼이 모두 인덱스에 있으면 탄다고 보는 것. 순서가 규칙을 정합니다.

Q.복합 인덱스에서 컬럼 순서를 어떻게 결정하나요?

기준내용
등가 조건을 앞에범위 조건은 그 뒤부터 인덱스를 못 쓰게 만든다
선택도가 높은 것을 앞에걸러내는 힘이 큰 컬럼이 앞에 오면 탐색 범위가 줄어든다
자주 쓰는 조합을 앞에하나의 인덱스로 여러 쿼리를 덮을 수 있다
ORDER BY 컬럼을 뒤에정렬까지 인덱스로 해결하면 추가 정렬이 사라진다

첫 번째가 가장 강한 규칙입니다.

WHERE status = 'paid' AND created_at > ?
INDEX (status, created_at)   -- 좋다
INDEX (created_at, status)   -- 범위 뒤라 status 를 못 쓴다

선택도는 실제 데이터로 확인합니다. status 값이 두 개뿐이면 앞에 두어도 절반밖에 못 거릅니다.

흔한 실수: 무조건 카디널리티가 높은 컬럼을 앞에 두는 것. 등가와 범위의 구분이 우선이고, 그 다음이 선택도입니다.

Q.WHERE A = ? AND C = ? 쿼리가 INDEX(A, B, C)를 활용할 수 있나요?

A 까지만 활용합니다. B 가 빠져 C 의 정렬이 보장되지 않기 때문입니다.

INDEX (A, B, C) 의 정렬 순서

A=1, B=1, C=5
A=1, B=2, C=3     <- A 가 같아도 C 는 뒤죽박죽이다
A=1, B=2, C=9

A 로 범위를 좁힌 뒤 그 안에서 C 조건은 하나씩 확인해야 합니다. 인덱스를 타긴 하지만 C 는 걸러내는 데만 쓰이고 탐색 범위를 줄이지는 못합니다.

실행 계획에서 확인할 수 있습니다. 인덱스에서 실제로 사용한 길이를 보면 A 의 크기만 잡힙니다.

개선하려면 INDEX (A, C) 를 따로 만들거나, 그 쿼리가 중요하면 컬럼 순서를 바꿉니다.

흔한 실수: 아예 못 탄다고 답하는 것. A 로는 탑니다. 어디까지 쓰는지를 구분해 답하는 것이 요지입니다.

먼저 스스로 답해보고 아래 답변과 견줘보세요. 막히는 부분은 문제로 확인할 수 있어요.

읽었으면 문제로 확인해보세요

데이터베이스 문제를 풀면 틀린 문제가 자동으로 노트에 쌓입니다. 가입 없이 5문제를 먼저 풀어볼 수도 있어요.