인덱스의 역할 — 왜 튜닝에서 중요한가?
SQL 튜닝의 80%는 불필요한 Full Table Scan을 줄이고, 인덱스를 효과적으로 활용하는 데서 시작됩니다. 인덱스 구조와 성능 특성을 이해하면, 실행 계획을 읽고 "왜 인덱스를 안 타는지" 바로 원인을 찾을 수 있습니다.
인덱스 내부 구조와 동작 방식
1 B-Tree 인덱스 (Balanced Tree)
- 대부분의 RDBMS가 사용하는 기본 인덱스 구조
- 검색, 정렬, 범위 조회에 유리
- 구조: 루트 노드 → 브랜치 노드 → 리프 노드
- 리프 노드에는 실제 데이터의 주소(RowID) 저장
튜닝 포인트
- 인덱스 범위를 최소화하면 블록 I/O를 줄일 수 있음
- "선행 컬럼" 조건이 실행 계획의 인덱스 활용 여부를 결정
2. 클러스터형 vs 비클러스터형
구분 | 클러스터형 인덱스 | 비클러스터형 인덱스 |
저장 방식 | 데이터 자체가 인덱스 순서로 저장 | 인덱스와 데이터가 별도로 존재 |
특징 | PK 자동 생성, 범위 조회 빠름 | 다수 생성 가능, 다양한 검색 조건 지원 |
튜닝 포인트 | 범위 스캔 최적 | 랜덤 I/O가 많을 경우 주의 |
3. 해시 인덱스
- 해시 함수를 사용해 검색 (정확한 값 검색에 특화)
- 범위 조회, 정렬 불가
- 주로 메모리 기반 DB, 또는 해시 파티션에서 사용
튜닝 포인트
- "=" 조건 최적화에 강력하지만, BETWEEN, LIKE는 비효율
인덱스 튜닝 전략
1. 고카디널리티(High Cardinality) 컬럼 우선
- 카디널리티: 컬럼의 고유 값 개수
- 값이 다양할수록(중복도 낮음) 인덱스 효율 ↑
- 예: 주민번호, 주문ID
2. WHERE 절에 인덱스 타게 만들기
- 인덱스 컬럼에 가공 연산 금지
-- 인덱스 미사용 예시
WHERE SUBSTR(phone, 1, 3) = '010'
-- 인덱스 사용 가능 예시
WHERE phone LIKE '010%'
- OR 조건보다는 UNION ALL + 개별 인덱스 활용이 효율적일 수 있음
3. 복합 인덱스 최적화
- 인덱스 순서 = 조건절 순서가 아님
- 선두 컬럼(Leading Column) 기준으로만 인덱스 사용
-- 인덱스 (col1, col2)인 경우
WHERE col1 = 'A' -- 인덱스 사용
WHERE col2 = 'B' -- 인덱스 사용 못함
4. 인덱스 스캔 방식 이해
스캔 방식 | 특징 | 튜닝 시 고려 |
Index Range Scan | 범위 조건 검색 | 가장 효율적 |
Index Unique Scan | 유일 값 검색 | PK, Unique 인덱스에 사용 |
Index Full Scan | 전체 인덱스 읽기 | 인덱스가 작은 경우 허용 가능 |
Index Skip Scan | 선두 컬럼 없이도 인덱스 일부 사용 | 효율이 낮아 조심 |
성능 저하를 유발하는 인덱스 사용 사례
- 테이블이 너무 작아 FTS가 더 빠를 때
- DML이 많은 컬럼에 인덱스 과다 생성
- LIKE '%값' → 인덱스 미사용 (전방 일치만 사용 가능)
- 불필요하게 많은 중복 값 컬럼 인덱스 생성
튜닝 팁 — 실행 계획으로 확인
- EXPLAIN PLAN 또는 AUTOTRACE 사용
- 인덱스를 타지 않는 경우, 함수 사용 여부·데이터 타입 변환·조건절 순서 등을 점검
- 인덱스 힌트 활용 (INDEX, INDEX_DESC)는 최후의 수단
인덱스는 칼과 같습니다. 잘 쓰면 조회 속도가 100배 빨라지지만, 잘못 쓰면 DML 성능이 반토막 나고 디스크를 잡아먹습니다.
SQL 튜닝에서는 "어떤 인덱스를 만들지"보다 "어떻게 태울지"가 더 중요합니다.