여러 컬럼을 묶어 인덱스를 만들 때 "어떤 컬럼을 앞에 둘까?"는 성능에 직접적인 영향을 줍니다. 순서를 잘못 정하면 인덱스를 만들어도 제대로 활용되지 않는 경우가 많습니다. 아래 기준들을 순서대로 점검해보면 도움이 됩니다.
1. 등치(=) 조건 컬럼을 range(범위) 조건 컬럼보다 앞에
복합 인덱스는 왼쪽부터 순서대로 값이 정렬되어 저장됩니다. = 조건은 인덱스에서 정확히 한 지점을 찾아가지만, BETWEEN, >, <, LIKE 'abc%' 같은 범위 조건은 그 지점 이후를 "훑는" 방식이라 그 뒤에 오는 컬럼은 정렬 순서가 깨집니다.
-- 쿼리
WHERE status = 'active' AND created_at > '2026-01-01'
-- 좋은 인덱스: (status, created_at)
-- 나쁜 인덱스: (created_at, status)
(created_at, status) 순서면 created_at 범위 검색 이후 status 조건은 인덱스만으로 필터링이 안 되고, 해당 범위 내 모든 행을 다시 확인해야 합니다.
2. 선택도(Selectivity, 카디널리티)가 높은 컬럼을 앞에... 이지만 절대적이진 않다
흔히 "카디널리티(고유값 개수)가 높은 컬럼을 앞에 두라"는 조언을 많이 듣습니다. 필터링 효과가 커서 스캔 범위를 빠르게 줄여주기 때문입니다. 하지만 이 규칙은 다음 두 가지 이유로 항상 정답은 아닙니다.
- 실제 쿼리 패턴이 우선: 카디널리티가 낮아도 항상 WHERE에 등치 조건으로 들어가는 컬럼이라면, 그 컬럼을 앞에 두는 게 실용적입니다.
- 정렬(ORDER BY) 요구사항: 인덱스로 정렬을 대체하려면(파일 정렬 회피) ORDER BY에 쓰이는 컬럼의 위치가 카디널리티보다 더 중요할 수 있습니다.
즉, "선택도"는 여러 기준 중 하나일 뿐, 실제 서비스의 쿼리 패턴을 먼저 봐야 합니다.
3. 자주 사용되는 쿼리 패턴 기준으로 설계
인덱스는 이론이 아니라 실제로 어떤 쿼리가 얼마나 자주 실행되는지에 맞춰 설계해야 합니다.
- 가장 자주 실행되는 쿼리부터 우선순위를 매긴다.
- 여러 쿼리가 공유하는 컬럼(예: tenant_id, user_id 같은 필터)을 왼쪽에 두면 하나의 인덱스로 여러 쿼리를 커버할 수 있다.
- "왼쪽 접두사(leftmost prefix)" 원칙을 기억하기: (a, b, c) 인덱스는 a, (a,b), (a,b,c) 조건 조회에는 쓰이지만, b만 조회하거나 (b, c) 조합 조회에는 쓰이지 않는다.
4. 정렬(ORDER BY)까지 고려한 커버링 설계
WHERE뿐 아니라 ORDER BY, GROUP BY까지 인덱스로 처리하고 싶다면, 정렬 대상 컬럼을 등치 조건 컬럼 바로 뒤에 배치합니다.
-- 쿼리
WHERE tenant_id = 10 ORDER BY created_at DESC
-- 인덱스: (tenant_id, created_at)
이렇게 하면 별도의 filesort 없이 인덱스 순서 그대로 정렬된 결과를 가져올 수 있습니다.
5. 커버링 인덱스(Covering Index)로 확장
자주 조회되는 컬럼들을 인덱스에 포함시켜, 테이블(실제 데이터, 예: InnoDB 클러스터드 인덱스)까지 가지 않고 인덱스만으로 쿼리를 끝낼 수 있게 만드는 것도 고려할 만합니다. 다만 인덱스에 컬럼을 추가할수록 쓰기(INSERT/UPDATE) 비용과 저장 공간이 늘어나므로, 조회 빈도와 트레이드오프를 따져야 합니다.
정리: 순서를 정하는 체크리스트
- 등치(=) 조건 컬럼을 범위 조건 컬럼보다 앞에 둔다.
- 실제 쿼리에서 가장 자주 쓰이는 필터 컬럼을 우선한다 (카디널리티는 참고 기준일 뿐).
- 여러 쿼리가 함께 쓰는 공통 필터 컬럼을 앞쪽에 배치해 인덱스 재사용성을 높인다.
- ORDER BY / GROUP BY 대상 컬럼은 등치 조건 컬럼 바로 뒤에 둬서 filesort를 피한다.
- 필요하다면 커버링 인덱스로 확장해 테이블 접근 자체를 없앤다.
결국 복합 인덱스 설계는 "이론적으로 카디널리티가 높은 순서"보다 **실제 쿼리 패턴(WHERE, ORDER BY, 접근 빈도)**을 기준으로 결정하는 것이 핵심입니다. EXPLAIN으로 실행 계획을 확인하며 반복적으로 검증하는 과정이 반드시 필요합니다.
'CS 정리' 카테고리의 다른 글
| select 조회 속도가 느리면 뭐부터 확인해야할까? (0) | 2026.09.04 |
|---|---|
| 이벤트 루프란? 싱글 스레드는 어떻게 수많은 요청을 처리할까 (0) | 2026.09.01 |
| DNS TTL이란? TTL을 300초로 설정하면 정말 5분 뒤에 IP가 바뀔까? (0) | 2026.08.31 |
| Cache-Aside를 실무에서 사용하면 어떤 문제가 생길까? (0) | 2026.08.29 |
| Cache-Aside란? (0) | 2026.08.28 |