여러 컬럼을 순서대로 묶어 만든 하나의 인덱스. (a, b, c) 처럼 정의한다.
어떻게 정렬되어 있나 — 이것이 모든 규칙의 근거
(부서, 입사일) 인덱스는 전화번호부처럼 정렬된다.
영업 2020-01 영업 2021-03 영업 2022-07 인사 2019-05 인사 2023-02 개발 2020-11
부서로 먼저 정렬하고, 같은 부서 안에서 입사일로 정렬한다. 성으로 정렬한 뒤 이름으로 정렬한 전화번호부와 똑같다.
좌측 접두 규칙
전화번호부에서 "이름이 철수인 사람" 을 찾으려면? 성을 모르면 처음부터 다 봐야 한다. 인덱스도 같다.
| 조건 | 활용 | 이유 |
|---|---|---|
부서 = '영업' | ○ | 정렬 첫 기준 |
부서 = '영업' AND 입사일 > '2021' | ○ | 부서로 좁힌 뒤 그 안에서 범위 |
입사일 > '2021' | ✗ | 부서를 모르면 흩어져 있다 |
범위 조건 뒤는 못 탄다
(a, b, c) 인덱스에 a = 1 AND b > 10 AND c = 5 를 걸면
- a=1 로 좁힘 — ← 인덱스 활용 b > 10 범위 스캔 ← 인덱스 활용 c = 5 ← 못 탄다. b가 범위라 c는 흩어져 있다
b > 10인 구간 안에서 c는 정렬되어 있지 않기 때문이다. c는 읽어서 걸러내는
필터링만 된다.
그래서 등호 조건 컬럼을 앞에, 범위 조건을 뒤에 두는 것이 설계 원칙이다.
순서를 정하는 기준
- 등호(
=)로 쓰는 컬럼 먼저 - 그중 카디널리티가 높은(값이 다양한) 것 먼저 — 더 많이 걸러낸다
- 범위 조건 컬럼
ORDER BY에 쓰이는 컬럼을 붙이면 정렬 비용까지 없앤다 (실행계획에서Using filesort가 사라진다)
흔한 오해
"(a,b) 인덱스가 있으면 조건도 a, b 순서로 써야 하나?"
→ 아니다. WHERE b = 2 AND a = 1 로 써도 옵티마이저가 재배열한다.
중요한 것은 인덱스 컬럼 순서와 조건에 등장하는 컬럼 집합이지 SQL의 작성 순서가 아니다.
"(a,b) 인덱스와 (a) 인덱스를 둘 다 만들어야 하나?"
→ 불필요하다. (a,b)가 a 단독 조회도 커버한다(좌측 접두). 오히려 중복 인덱스는
쓰기 비용과 저장 공간만 늘린다.