반응형
1. 실행계획은 어떻게 읽어야 하나
실행계획은 위에서 아래로 읽지 않는다. 안쪽(오른쪽, 가장 아래)부터 바깥쪽으로 실행된다.
즉, 성능은 항상 첫 테이블 접근 방식에서 대부분 결정된다.
2. 실행계획에서 반드시 봐야 하는 핵심 지표
Rows (Cardinality)
- 옵티마이저가 "이 단계에서 몇 건이 나올 것"이라 예상한 값
- 실행계획의 모든 판단 기준
Rows가 틀리면 조인 방식, 인덱스 선택, 실행 순서 전부 틀어진다.
E-Rows vs A-Rows
- E-Rows: 예상 행 수
- A-Rows: 실제 실행 행 수
5~10배 이상 차이면 무조건 튜닝 대상
3. 테이블 접근 방식 한 줄 요약
- TABLE ACCESS FULL
→ 테이블 전체를 읽음. 대량 데이터면 위험 신호 - TABLE ACCESS BY ROWID
→ 인덱스로 위치를 찾은 뒤 테이블 접근
4. 인덱스 스캔 방식 정리 (한 줄 요약)
- INDEX UNIQUE SCAN
→ PK/UK 조회. 가장 이상적인 형태 - INDEX RANGE SCAN
→ 조건 범위에 해당하는 인덱스 구간만 탐색 - INDEX FULL SCAN
→ 인덱스를 처음부터 끝까지 읽음 (대체로 좋지 않음) - INDEX FAST FULL SCAN
→ 인덱스를 정렬 무시하고 통째로 읽음 (집계용)
5. WHERE 조건과 인덱스의 관계
인덱스는 WHERE 조건으로 얼마나 줄일 수 있느냐가 전부다.
좋은 조건
WHERE user_id = :id
→ 선택도 높음, 인덱스 효과 큼
나쁜 조건
WHERE status = 'Y'
→ 값 종류 적음, 단독 인덱스 의미 거의 없음
6. JOIN 조건에서 인덱스는 언제 필요한가
JOIN 인덱스의 목적은 하나다.
NESTED LOOP를 가능하게 만드는 것
- 자식 테이블(FK 쪽)에 인덱스 필수
- 부모 테이블은 PK로 충분한 경우가 대부분
7. 복합 인덱스와 선두 컬럼의 의미
INDEX (A, B, C)
이 인덱스는 내부적으로 A → B → C 순으로 정렬된다.
제대로 타는 경우
WHERE A = 1 AND B = 10
선두 컬럼을 못 쓰는 경우
WHERE B = 10
→ A 조건이 없으면 인덱스는 사실상 무력화된다.
8. 범위 조건이 끼면 그 뒤 컬럼은 사용 불가
WHERE A = 1
AND B BETWEEN 10 AND 20
AND C = 5
- A: 사용
- B: 사용
- C: 인덱스 탐색 불가
= 조건 → 범위 조건 → 이후 컬럼은 장식
9. 인덱스를 만들어도 성능이 안 나오는 대표적인 이유
- 결과 행이 너무 많음 (선택도 낮음)
- 함수 / 가공으로 인덱스 무력화
- 복합 인덱스 선두 컬럼 누락
- 컬럼 타입 불일치
- 통계 정보 오류
- LIKE '%값' 패턴
- 조인 순서 자체가 잘못됨
10. 인덱스를 많이 만들면 왜 느려질까
- INSERT / UPDATE / DELETE 시 인덱스 전부 갱신
- 인덱스 블록 락 경합 증가
- 옵티마이저 선택지 과다 → 오판 확률 증가
- 버퍼 캐시 낭비
인덱스는 읽기 성능 도구이자 쓰기 성능 부채다.
11. 실행계획 문제는 결국 WAS 장애로 이어진다
잘못된 실행계획 →
- 쿼리 지연
- 트랜잭션 장기 유지
- 커넥션 점유 증가
- HikariCP active 상승
- Connection timeout 발생
실행계획 튜닝은 DB 문제가 아니라 서비스 안정성 문제다.
12. 정리
- 실행계획은 Cost가 아니라 Rows를 본다
- 인덱스는 선두 컬럼부터 연속으로 써야 의미 있다
- 인덱스는 많을수록 위험하다
"실행계획을 못 보면 장애 원인을 절반도 못 본다."
반응형
'IT' 카테고리의 다른 글
| @Async 적용하기 (0) | 2026.01.14 |
|---|---|
| 커넥션 타임아웃과 리드 타임아웃 (0) | 2026.01.13 |
| 실서비스에서 커넥션 풀(hikari Cp) 제대로 이해하기 (0) | 2025.12.16 |
| Business Exception vs System Exception (0) | 2025.12.15 |
| Spring @ControllerAdvice 완전 정리 (0) | 2025.12.15 |
댓글