MySQL/InnoDB 인덱스는 면접과 실무 모두에서 "어떻게 동작하는가(구조)"와 "왜 내 쿼리는 느린가(운영)" 두 축으로 반복해서 등장한다. 이 문서는 인덱스 종합 허브로서 각 축의 핵심만 짧게 정리하고, 심화는 아래 상세 문서로 내려가게 한다. - 저장 구조 · 버퍼 풀 · MVCC 같은 엔진 내부는 → InnoDB 스토리지 엔진 아키텍처 - 복합...
MySQL/InnoDB 인덱스는 면접과 실무 모두에서 "어떻게 동작하는가(구조)"와 "왜 내 쿼리는 느린가(운영)" 두 축으로 반복해서 등장한다. 이 문서는 인덱스 종합 허브로서 각 축의 핵심만 짧게 정리하고, 심화는 아래 상세 문서로 내려가게 한다.
이 허브에서는 "개념 한 번, 링크 한 번" 원칙으로 같은 설명을 반복하지 않는다.
면접에서 바로 꺼낼 수 있어야 하는 최소 지식.
Extra: Using index로 확인.페이지 구조, 버퍼 풀, 리두/언두 같은 엔진 내부 동작은 innodb-storage-architecture.md에서 다룬다.
| 종류 | 정의 | 언제 쓰나 |
|---|---|---|
| 클러스터드 인덱스(PK) | 리프에 실제 row. 테이블당 1개 | 모든 InnoDB 테이블에 필수. 단조 증가 + 불변 + 짧게 |
| 세컨더리 인덱스 | 리프에 (키, PK). 테이블당 N개 | WHERE/JOIN/ORDER BY에서 자주 쓰이는 컬럼 |
| 복합 인덱스 | 여러 컬럼을 한 키로 | 조건이 2개 이상인 쿼리. 좌측 접두사 규칙 준수 |
| 커버링 인덱스 | SELECT 전 컬럼이 인덱스에 존재 | 고빈도·컬럼 고정 조회. 쓰기 비용 트레이드오프 |
| 유니크 인덱스 | 값 중복 금지 | 비즈니스 유일성 보장. 옵티마이저에 const/eq_ref 힌트 |
| FULLTEXT | 역색인 기반 텍스트 검색 | LIKE '%키워드%' 대체. 본격 검색은 Elasticsearch 고려 |
INDEX idx (a, b, c)의 리프는 a → 같은 a 내 b → 같은 (a,b) 내 c 순서로 정렬된다. 이 물리 구조가 좌측 접두사 규칙의 근거다.
| 쿼리 조건 | 사용 | 비고 |
|---|---|---|
a = ? | a | 선두 컬럼 |
a = ? AND b = ? | a, b | 좌측부터 연속 |
a = ? AND b = ? AND c = ? | a, b, c | 모두 사용 |
b = ? AND c = ? | 미사용 | 선두 컬럼 없음 |
a = ? AND c = ? | a만 | b 건너뜀 → c는 인덱스 활용 X |
a = ? AND b > ? AND c = ? | a, b까지 | 범위 이후 컬럼은 인덱스 활용 X |
=) 조건 컬럼을 앞에>, <, BETWEEN) 컬럼을 뒤에ORDER BY / GROUP BY 컬럼을 범위 뒤에 (filesort 회피)선택도만 보고 순서를 정하는 건 흔한 오답이다. 쿼리 패턴이 우선. 근거, 실습, 실패 사례, EXPLAIN
key_len역산법 등은 composite-index.md 참고.
인덱스를 "만들었다"로 끝내면 안 된다. EXPLAIN으로 실제로 타는지 확인하는 습관이 실력이다.
| 컬럼 | 본다는 의미 |
|---|---|
type | const/eq_ref/ref/range 좋음, index 나쁨, ALL 풀스캔 |
key | 실제 선택된 인덱스 |
key_len | 인덱스 바이트 수 → 몇 컬럼 사용했는지 역산 가능 |
rows × filtered/100 | 다음 단계로 넘어갈 예상 행 수 |
Extra | Using index(커버링), Using filesort(정렬 인덱스 미사용), Using index condition(ICP) |
EXPLAIN → type이 ALL/index인지, key가 기대한 인덱스인지, key_len이 기대한 컬럼 수만큼인지 확인Extra에 Using filesort / Using temporary가 있으면 설계 재검토EXPLAIN ANALYZE + ANALYZE TABLE로 통계 갱신
key_len역산 공식,EXPLAIN ANALYZE트리 읽기, JPA N+1 vs JOIN FETCH EXPLAIN 비교, Aurora Reader 라우팅 영향은 explain-plan.md 참고.
실무 슬로우 쿼리의 상당수가 여기에 해당한다. 각 케이스의 상세 재현·수정·EXPLAIN 검증은 explain-plan.md 7장을 참고한다.
WHERE YEAR(created_at) = 2025 → 범위 조건으로 변환하거나 함수형 인덱스WHERE user_id = '42', VARCHAR 컬럼을 숫자와 비교 → 파라미터 타입을 컬럼 타입과 일치LIKE '%kim' → FULLTEXT / 외부 검색 엔진 / REVERSE 함수형 인덱스WHERE a = ? OR b = ? → UNION ALL로 분해WHERE status = 'ACTIVE'가 80% → 단독 인덱스 지양, 복합 인덱스 뒷부분에 포함(a,b,c)에 WHERE b = ? → 새 인덱스 or 컬럼 순서 재설계(a,b,c)에 a = ? AND b > ? AND c = ? → 동등 컬럼을 앞으로 ((a,c,b))Using filesort → 정렬 컬럼을 인덱스 뒷부분에 포함, 필요하면 내림차순 인덱스ANALYZE TABLE 우선, FORCE INDEX는 최후!=, NOT IN, <> — 범위 표현 곤란 → 가능하면 긍정 조건(IN (...)) 으로 재작성column = NULL은 틀린 문법. IS NULL은 인덱스 탈 수 있으나 선택도 극단 시 풀스캔"인덱스 걸었는데도 느립니다, 어떻게 보세요?"에 바로 쓸 수 있는 흐름.
EXPLAIN: type, key, key_len, Extra 확인EXPLAIN ANALYZE로 예측 vs 실제 비교 → 차이 크면 ANALYZE TABLEALGORITHM=INPLACE, LOCK=NONE), Aurora Reader 지연 모니터링OPTIMIZE TABLE 가능하지만 락/복제 지연 주의.ANALYZE TABLE을 의식적으로 호출한다. 통계가 낡으면 옵티마이저가 잘못된 플랜을 고른다.ALGORITHM=INPLACE, LOCK=NONE 확인, 필요 시 pt-online-schema-change / gh-ost.버퍼 풀 크기, 더티 페이지 플러시, 체크포인트 에이지, 리두 로그 연관 동작은 innodb-storage-architecture.md에서 다룬다.
"InnoDB는 B+Tree를 씁니다. 리프에만 값이 있고 리프끼리 양방향 링크로 연결돼 범위 검색이 효율적이고, 16KB 페이지에 키를 많이 담아 트리 높이가 3~4단계로 낮아 100만 행에서도 PK 조회가 디스크 I/O 몇 번으로 끝납니다. InnoDB는 PK 자체가 테이블 구조(클러스터드 인덱스)이고, 세컨더리 인덱스는 리프에 PK를 담아 두 번 탐색으로 행을 읽습니다. 필요한 컬럼이 모두 인덱스에 있으면 이 두 번째 탐색이 사라지는데, 이걸 커버링 인덱스라 하고 EXPLAIN
Extra: Using index로 확인합니다."
"EXPLAIN부터 봅니다.
type이ALL/index인지,key가 의도한 인덱스인지,key_len이 기대한 컬럼 수만큼인지,Extra에Using filesort/Using temporary가 있는지 확인합니다. 원인은 패턴이 정해져 있어서 — 컬럼에 함수/연산, 암묵적 타입 변환, LIKE 선두 와일드카드, OR 분기, 좌측 접두사 위반, 범위 조건 뒤 동등 조건 등 — 분류한 뒤 쿼리 재작성 → 인덱스 추가 → 인덱스 재설계 순으로 가벼운 조치부터 시도하고, 수정 후 반드시 EXPLAIN으로 재검증합니다."
"쿼리 패턴이 우선이고 선택도는 그 다음입니다. 동등 조건 컬럼을 앞에, 범위 조건을 뒤에, ORDER BY 컬럼을 마지막에 둡니다. 범위 이후 컬럼은 인덱스 연속성이 깨져 활용이 안 되기 때문입니다. 설계 후 EXPLAIN
key_len으로 의도한 컬럼 수만큼 잡히는지 확인합니다. 심화 기준과 실제 설계 예시는 별도로 정리해뒀습니다."
"읽기 빈도가 매우 높고 SELECT 컬럼이 고정된 핫 쿼리에 선별 적용합니다. 세컨더리 인덱스 리프에 PK가 있으니 SELECT 대상이 모두 인덱스 안에 있으면 클러스터드 인덱스 재조회(랜덤 I/O)가 사라집니다. 다만 인덱스가 비대해지고 쓰기 비용이 늘어나므로 모든 조회에 적용하지는 않습니다."
type이 ALL/index가 아닌가key가 의도한 인덱스인가key_len이 기대한 컬럼 수만큼인가Extra에 Using filesort / Using temporary가 없는가 (있다면 그래야만 하는 이유가 있는가)ANALYZE TABLE로 통계가 최신인가