복합 인덱스를 만들었는데 조건 순서를 바꿨더니 안 쓰인 이유
문제 발생
(status, created_at) 복합 인덱스를 만들었는데, 어떤 쿼리는 빠르고 어떤 쿼리는 풀 스캔이었습니다.
-- 빠르다
SELECT * FROM posts WHERE status = 'published' AND created_at > '2026-01-01';
-- 인덱스를 안 쓴다
SELECT * FROM posts WHERE created_at > '2026-01-01';원인 분석
복합 인덱스는 선행 컬럼부터 차례로 정렬된 하나의 구조입니다. 전화번호부가 성 → 이름 순으로 정렬된 것과 같아서, 성을 모르면 이름만으로는 찾을 수 없습니다.
MySQL 매뉴얼은 이를 가장 왼쪽 접두사(leftmost prefix) 규칙으로 설명합니다 — 인덱스를 쓰려면 WHERE의 각 AND 그룹에서 인덱스의 접두사가 사용되어야 합니다.
(part1, part2, part3) 인덱스 기준으로:
| 조건 | 인덱스 사용 |
|---|---|
part1=1 AND part2=2 AND other=3 | 사용 (part1, part2까지) |
part1='hello' AND part3=5 | 사용 (part1까지만) |
part2=1 AND part3=2 | 사용 못 함 (선행 컬럼 없음) |
part1=1 OR part2=10 | 사용 못 함 |
같은 원리가 LIKE에도 적용됩니다. 매뉴얼에 따르면 LIKE의 인자가 와일드카드로 시작하지 않는 상수 문자열일 때만 B-tree 인덱스를 쓸 수 있습니다.
WHERE key_col LIKE 'Patrick%' -- 사용 ('Patrick' <= key_col < 'Patricl' 범위)
WHERE key_col LIKE '%Patrick%' -- 사용 못 함
WHERE key_col LIKE other_col -- 사용 못 함 (상수가 아님)해결 방안
- 자주 쓰는 조건의 컬럼을 앞에 둡니다. 등호 조건이 범위 조건보다 앞에 오는 것이 보통 유리합니다 — 범위 조건 뒤의 컬럼은 인덱스 탐색에 쓰이지 못하기 때문입니다.
- 선행 컬럼 없이 조회하는 패턴이 있으면 별도 인덱스를 만듭니다.
(created_at)인덱스를 추가하는 식입니다. 다만 인덱스마다 쓰기 비용과 저장 공간이 늘어나므로 실제로 쓰이는 패턴만 만듭니다. (a, b)가 있으면(a)는 따로 만들지 않습니다. 접두사 규칙 때문에 이미 커버됩니다. 반대로(b)가 필요하면 별도로 만들어야 합니다.- 앞뒤 와일드카드 검색이 요구사항이면 다른 도구를 봅니다.
LIKE '%키워드%'는 구조적으로 인덱스를 못 씁니다. 전문 검색 인덱스(FULLTEXT)나 검색 엔진이 맞는 자리입니다. 이 저장소의 노트 검색도 데이터 규모가 작아 LIKE로 두고 있지만, 커지면 이 지점을 다시 봐야 합니다. - 추측하지 말고
EXPLAIN으로 확인합니다. 어떤 인덱스가 선택됐는지, 몇 행을 훑는지가 나옵니다. 인덱스를 만들었다는 사실과 실제로 쓰인다는 사실은 별개입니다.
댓글0
댓글을 남기려면 로그인이 필요해요. 로그인
아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.