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을 사용할 때는 항상 쿼리 개수를 확인하는 습관이 필요하다.

Django ORM N+1 쿼리 문제 해결