인덱스 핵심 개념 정리
원하는 데이터를 빠르게 조회하기 위한 자료구조
테이블과는 별도로 저장됨
일반적으로 B-Tree 구조 사용
PRIMARY KEY, UNIQUE 제약 조건 컬럼에는 자동 생성
인덱스 적용 전 / 후 차이
| 구분 | 인덱스 없음 | 인덱스 있음 |
|---|---|---|
| 검색 방식 | 전체 테이블 탐색(Full Scan) | 인덱스 탐색 |
| 시간 복잡도 | O(n) | O(log n) |
| I/O 비용 | 매우 높음 | 낮음 |
| 추가 저장 공간 | 없음 | 필요 |
| INSERT/UPDATE 성능 | 빠름 | 약간 느려짐 |
인덱스 실습
사용자 테이블에 대량 데이터(천만 건) 생성
인덱스 미적용 상태에서 조회 시 전체 테이블 스캔 발생
name 컬럼에 인덱스 생성 후
→ 동일 조건 조회가 인덱스 탐색으로 전환되어 속도 개선
CREATE INDEX idx_user_name ON user(name);
정리
인덱스는 조회 성능을 비약적으로 향상시키지만,
무분별하게 사용하면 쓰기 성능 저하와 공간 낭비를 유발한다.
자주 조회되는 컬럼에만 전략적으로 적용하는 것이 중요✨
인덱스는 단순한 정렬이 아님
단순 정렬: 처음부터 끝까지 순차 탐색
B-Tree 인덱스: 분기(branch)를 따라 필요한 범위만 탐색
탐색 비용은 트리 높이에 비례 → O(log n)
B-Tree 인덱스 동작 원리
루트 → 중간 노드 → 리프 노드 순으로 비교
불필요한 데이터는 건너뛰고 정확한 경로만 탐색
Full Scan 대비 수백~수천 배 빠름
인덱스 스캔 종류 요약
PK / UNIQUE 컬럼 조회
정확히 한 건 탐색
가장 빠름
SELECT * FROM users WHERE id = 10;
범위 조건 조회
시작 위치 탐색 후 연속 읽기
정렬된 인덱스 덕분에 ORDER BY 효율적
WHERE age BETWEEN 20 AND 30
WHERE name LIKE 'abc%'
인덱스 전체를 순서대로 탐색
WHERE 조건은 없지만 ORDER BY 최적화 가능
SELECT * FROM users ORDER BY name;
조건 일부를 인덱스 단계에서 미리 필터링
테이블 접근 횟수 감소 → 디스크 I/O 절약
WHERE status = 'PAID' AND order_date > '2025-11-01'
인덱스를 전혀 사용하지 못하는 경우
모든 행을 직접 비교 → 가장 느림
WHERE city = 'Seoul' -- 인덱스 없음
옵티마이저 역할
DB가 가장 효율적인 실행 계획을 자동 선택
개발자는 인덱스 설계만 신경 쓰면 됨
실제 사용 여부는 옵티마이저 판단
인덱스의 한계
결론
인덱스 유무에 따라 실행 계획(EXPLAIN)이 완전히 달라짐
PK → Unique Scan
범위 조건 → Range Scan
인덱스 없음 → Full Table Scan
요약
인덱스는 단순 정렬이 아닌 B-Tree 기반 탐색 구조이며,
조회 성능을 극적으로 개선하지만 쓰기 비용과 공간을 고려해 설계해야 한다.
복합 인덱스(Composite Index) 정의
왜 복합 인덱스가 필요한가?
단일 인덱스는 하나의 컬럼 기준 정렬만 가능
실무에서는 보통 여러 조건을 함께 조회
예: start_date + end_date
복합 인덱스의 핵심 규칙
왼쪽 접두어 규칙 (Leftmost Prefix Rule)
복합 인덱스는 왼쪽(선두) 컬럼부터 순서대로만 사용된다.
(start_date, end_date)
start_date 기준으로 먼저 정렬
같은 start_date 내에서 end_date 정렬
인덱스 사용 가능 여부 요약
| WHERE 조건 | 인덱스 사용 |
|---|---|
| a | ✅ |
| a, b | ✅ |
| a, b, c | ✅ |
| b | ❌ |
| b, c | ❌ |
포인트
(start_date, end_date) 인덱스
start_date + end_date 조건 → ✅ 인덱스 사용
end_date 단독 조건 → ❌ Full Table Scan
인덱스 순서를 바꾸면 사용은 되더라도
쿼리 패턴과 맞지 않으면 비효율적
복합 인덱스가 특히 유용한 경우
항상 함께 조회되는 컬럼들
WHERE + ORDER BY를 동시에 만족해야 할 때
페이징 쿼리 성능이 중요한 경우
대표 예시
(category_id, price) → 상품 목록 + 정렬
(user_id, order_date) → 사용자별 기간 조회
(board_id, created_at) → 게시판 최신글
(region, district) → 지역 기반 검색
단일 인덱스 여러 개 vs 복합 인덱스
단일 인덱스 여러 개: 옵티마이저 조합 필요, 효율 낮음
복합 인덱스 하나: 한 번의 탐색으로 범위 축소
요약
복합 인덱스는 자주 함께 조회되는 컬럼을 하나의 B-Tree로 묶어,
왼쪽 접두어 규칙을 기반으로 조회·정렬 성능을 동시에 최적화한다.
목표
JOIN + GROUP BY 쿼리에서 인덱스 유무에 따른 실행 계획과 성능 차이를 확인한다.
테이블 구조 요약
users
id (PK)
username (UNIQUE → 자동 인덱스)
posts
id (PK)
user_id (FK 성격, 인덱스 없음)
comments
id (PK)
post_id (FK 성격, 인덱스 없음)
실행 쿼리
특정 username의 게시글 목록 조회
게시글별 댓글 수 집계
users → posts → comments LEFT JOIN + GROUP BY post.id
인덱스 없이 실행했을 때
문제점
posts, comments 모두 Full Table Scan
JOIN 컬럼에 인덱스가 없어 모든 행 탐색
전체 스캔량: 11 × 8 = 88행
EXPLAIN에서 꼭 볼 3가지
| 항목 | 의미 | 판단 기준 |
|---|---|---|
| type | 탐색 방식 | ALL ❌ / ref, const ✅ |
| key | 사용 인덱스 | NULL ❌ |
| rows | 예상 읽기 수 | 작을수록 좋음 |
인덱스 추가 후 실행 계획
개선 효과
Full Scan 제거
JOIN 대상만 정확히 탐색
전체 스캔량: 약 3~4행 수준
실행 시간: 100~200ms → 1~3ms
요약
JOIN 성능의 핵심은 WHERE 조건뿐 아니라
JOIN 컬럼(user_id, post_id)에 인덱스가 있는가이다.
EXPLAIN에서 ALL + NULL + rows 많음이면 → 인덱스 설계부터 의심하자.
공부하자...이제 쿼리 성능을 개선하는 법도 알게 되었다..! ( •̀ ω •́ )y