home

인덱스는 엑셀표가 아니다

인덱스를 구성할 때 인덱스 = 엑셀표 처럼 접근하는 오류를 많이 저지릅니다. 예를 들어봅시다.

WHERE dept_id=20 AND status='Active'

이러한 쿼리가 있을 때, 많은 사람들은 이런 식으로 생각합니다.

“dept_id로 먼저 필터링하면 100만 행 → 5만 행으로 줄고, 그 다음 status로 필터링하면 5만 행 → 1만 행으로 줄어든다. 반대로 status를 먼저 쓰면 100만 행 → 50만 행 → 1만 행이니까 dept_id를 선두 컬럼으로 해야 45만 행을 덜 읽는다!”

하지만 이건 엑셀 사고방식인데요, 실제 B+Tree는 이렇게 작동합니다.

인덱스(dept_id, status)의 경우

정렬 순서: (10,A), (10,I), (20,A), (20,A), (20,A), (20,I), (30,A)...
스캔 시작점: (20, Active)
스캔 종료점: (20, Active의 끝)
실제 스캔: 20-A-김, 20-A-영, 20-A-박 → 3개 행

인덱스(status, dept_id)의 경우

정렬 순서: (A,10), (A,20), (A,20), (A,20), (A,30), (I,10), (I,20)...
스캔 시작점: (Active, 20)
스캔 종료점: (Active, 20의 끝)
실제 스캔: A-20-김, A-20-영, A-20-박 → 3개 행

두 경우 모두 정확히 3개 행만 스캔합니다.

여기서 주목해야 할 B+Tree의 가장 중요한 특성이 있습니다.

  1. 모든 컬럼 조합으로 정렬되어 있다.
    • (dept_id, status) 순으로 정렬 = 모든 dept_id 값 내에서 status도 정렬됨
    • (status, dept_id) 순으로 정렬 = 모든 status 값 내에서 dept_id도 정렬됨
  2. 시작점과 종료점을 직접 찾는다.
    • 엑셀처럼 “위에서부터 하나씩 확인”하지 않음
    • B+Tree 탐색으로 조건에 맞는 첫 번째 위치로 점프
    • 조건에 맞지 않는 첫 번째 위치에서 멈춤
  3. 중간 필터링 과정이 없다.
    • “dept_id=20인 것들을 먼저 모으고…” X
    • “(20, Active) 범위를 바로 스캔” O

따라서 흔한 오해 과정을 정리해보면 다음과 같습니다.

엑셀 방식 (실제 동작 아님)

100만 행 전체 데이터
  ↓ dept_id = 20 필터링
5만 행
  ↓ status = Active 필터링
1만 행
  • 선두 컬럼에 따라 중간 단계의 행 수가 달라짐

B+Tree 방식

B+Tree 탐색으로 (20, Active) 위치 찾기
  ↓
해당 위치부터 순차 스캔
  ↓
(20, Active) 범위가 끝나면 멈춤
  • 선두 컬럼과 무관하게 최종 범위만 스캔

그렇다면 인덱스 순서는 무의미한가요?

당연히 아니죠. 다음과 같은 경우에는 순서가 중요합니다.

1. 범위 조건이 포함된 경우

WHERE dept_id = 20 AND salary > 5000000
  • 인덱스(dept_id, salary): (20, 5000000) ~ (20, 끝) → 최적
  • 인덱스(salary, dept_id): 여러 salary 범위를 각각 확인 → 비효율

범위 조건이 있는 컬럼은 뒤로가는게 좋아요

2. 한 컬럼만 사용하는 쿼리가 많은 경우

-- 쿼리 A (80%):
WHERE dept_id = 20
-- 쿼리 B (20%):
WHERE dept_id = 20 AND status = 'Active'
  • 인덱스(dept_id, status): 두 쿼리 모두 사용 가능
  • 인덱스(status, dept_id): 쿼리 A는 사용 불가

따라서 자주 쓰이는 컬럼은 앞으로 가는 것이 좋습니다.

3. 카디널리티가 극단적으로 다른 경우

WHERE gender = 'M' AND user_id = 12345
-- gender: 2개 값 (M/F)
-- user_id: 100만 개 값
  • 인덱스(user_id, gender): 1개 행으로 바로 점프
  • 인덱스(gender, user_id): 50만 개 행 중에서 찾기 시작

결론

따라서, 스캔량이 거의 비슷하고 모두 동일할 때는 인덱스 순서를 고려할 필요가 없어요. 하지만, 방금 보신 것과 같이 범위 조건이 있거나, 단독 사용하는 쿼리가 많거나, 카디널리티가 극단적으로 차이가 난다면 순서를 반드시 고려해야합니다.

인덱스를 위에서 아래로 필터링하는 엑셀과 같은 형태로 접근을 하는 순간, 잘못된 인덱스를 설계할 가능성이 큽니다. 다시 한번 강조하면

B+Tree는 다차원의 공간에서 조건에 맞는 연속된 영역을 찾아 스캔하는 구조입니다.

모든 컬럼이 등호 조건이면 인덱스 순서는 스캔량에 영향을 주지 않습니다. 하지만, 실무에서는 필드별로 많은 인덱스를 걸 수 없기 때문에 순서를 잘 고려해서 인덱스를 설계해야한다고 저는 생각합니다.