성능 개선일지 1 (feat. N+1, Index)
카테고리
프로그래밍/소프트웨어 개발
서브카테고리
데이터 분석
대상자
- *백엔드 개발자 및 DB 최적화에 관심 있는 개발자**
- *난이도**: 중급 (N+1 문제, 인덱스 최적화, JPA 쿼리 작성 기술 필요)
핵심 요약
- N+1 문제 해결을 통해 평균 응답 시간 18.32s → 0.35s로 98% 성능 개선
@Query
로 JOIN FETCH를 사용해 하나의 쿼리로 selections/schedules/events 테이블 연관 조회- 인덱스 적용은 schedules 테이블에서 효과 미미, selections 테이블에서는 FK 기반 자동 인덱스 존재
섹션별 세부 요약
1. 문제 진단 및 측정 환경
- Grafana K6로 20명 동시 사용자, 50번 호출 시 18.38s 평균 응답 시간 측정
- N+1 문제로 인한 반복 쿼리 발생 (예: `schedules_id=?" 반복 호출)
- 로그 분석 통해
member.getSelections()
→s.getSchedule()
호출 시 Lazy Loading으로 N+1 발생
2. N+1 문제 해결
- JPA FETCH JOIN 쿼리 작성
```java
@Query("SELECT s FROM Selection s JOIN FETCH s.schedule sc WHERE s.member = :member")
List
```
- 하나의 쿼리로 selections/schedules/events 테이블 연관 조회
```sql
SELECT s1_0.selections_id, s2_0.schedules_id, e1_0.events_id FROM selections s1_0 JOIN schedules s2_0 ON s2_0.schedules_id = s1_0.schedules_id JOIN events e1_0 ON e1_0.events_id = s2_0.events_id WHERE s1_0.users_id = ?
```
- 성능 개선: 평균 응답 시간 0.35s로 감소
3. 인덱스 최적화 시도
- selections 테이블:
users_id
,members_id
,schedules_id
에 인덱스 생성 (FK 자동 생성으로 효과 미미) - schedules 테이블:
date
,day
,time
에 인덱스 생성 → 카디널리티 낮음으로 인해 성능 개선 미비 - 복합 인덱스 시도:
date + time
,day + time
→ DB 옵티마이저 판단으로 인해 사용률 낮음 - 결론: schedules 테이블 인덱스는 효과 미미, selections 테이블은 FK 기반 자동 인덱스로 추가 필요 없음
결론
- N+1 문제 해결이 성능 개선의 핵심 →
JOIN FETCH
쿼리 사용 권장 - 인덱스 적용은 카디널리티와 사용 패턴 고려 필수 (예:
schedules
테이블 인덱스는 효과 미미) - 추가 최적화 방향: DTO Projection, Query DSL, 캐싱, 정규화/비정규화 고려 → 성능 향상의 잠재력 있음