Django ORM N+1 쿼리 문제 해결
문제 상황
사용자 목록 API의 응답 속도가 평균 3초 이상 걸리는 문제가 발생했다. 사용자가 100명 정도일 때는 괜찮았는데, 1000명을 넘어가면서 급격히 느려졌다.
Django Debug Toolbar로 확인해보니 쿼리가 1000개 이상 실행되고 있었다. 전형적인 N+1 쿼리 문제였다.
# 문제가 있던 코드
users = User.objects.all()
for user in users:
print(user.profile.bio) # 매번 쿼리 실행
print(user.posts.count()) # 매번 쿼리 실행
해결 방법
1. select_related (1:1, N:1 관계)
외래키나 OneToOne 관계는 select_related로 JOIN 쿼리 한 번에 가져온다.
users = User.objects.select_related('profile').all()
for user in users:
print(user.profile.bio) # 추가 쿼리 없음
2. prefetch_related (1:N, M:N 관계)
역참조나 ManyToMany 관계는 prefetch_related를 사용한다.
users = User.objects.prefetch_related('posts').all()
for user in users:
print(user.posts.count()) # 추가 쿼리 없음
3. 실전 적용
users = User.objects.select_related(
'profile'
).prefetch_related(
'posts',
'posts__comments'
).all()
결과
- 쿼리 수: 1203개 → 3개
- 응답 시간: 3.2초 → 0.3초
단순히 ORM 메서드 체이닝만 추가했는데 10배 이상 성능이 개선됐다. Django ORM을 사용할 때는 항상 쿼리 개수를 확인하는 습관이 필요하다.