기술블로그-Django편

🔍 Django ORM 쿼리 최적화 - select_related vs prefetch_related

Chansman 2025. 5. 14. 23:23

🔍 Django ORM 쿼리 최적화 - select_related vs prefetch_related

Django에서는 DB 성능 최적화를 위해 select_related()와 prefetch_related() 메서드를 제공합니다.
이번 글에서는 다음과 같은 코드를 기준으로:

queryset = Post.objects.all().select_related('user').prefetch_related('images')

두 함수의 차이점과 목적, 사용 시 주의사항을 정리합니다.


✅ 1. select_related('user') - 정참조 최적화

# Post 모델
user = models.ForeignKey(User, on_delete=models.CASCADE)
  • Post → User는 N:1의 정참조 관계입니다.
  • select_related('user')는 JOIN 쿼리를 통해 User 정보를 한 번에 가져옵니다.
  • 따라서 post.user.nickname 같은 접근 시 추가 쿼리 없이 처리됩니다.

💡 N+1 문제 해결 (반복 조회 시 매번 쿼리 발생 방지)

🔎 실행 예시

SELECT * FROM post_post
JOIN auth_user ON post_post.user_id = auth_user.id;

🔄 2. prefetch_related('images') - 역참조 최적화

# PostImage 모델
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='images')
  • Post ← PostImage는 1:N 역참조 관계입니다.
  • prefetch_related('images')는 두 번의 쿼리로 Post와 PostImage를 각각 불러오고,
    파이썬에서 post.id 기준으로 매핑합니다.

💡 post.images.all()을 여러 번 호출해도 DB 쿼리는 1회로 해결됩니다.

🔎 실행 예시

SELECT * FROM post_post;
SELECT * FROM post_postimage WHERE post_id IN (1, 2, 3, ...);

🧠 차이점 요약 정리표

항목 select_related prefetch_related

대상 관계 정참조 (1:1, N:1) 역참조 (1:N, M:N)
동작 방식 SQL JOIN 파이썬에서 매핑
쿼리 수 1회 2회
사용 위치 ForeignKey, OneToOne related_name, ManyToMany

✅ 결론 및 실전 팁

  • post.user.nickname처럼 외래키 대상 필드를 템플릿/뷰에서 자주 접근한다면 → select_related 사용
  • post.images.all처럼 역참조되는 다대일/다대다 관계를 템플릿에서 반복문으로 쓴다면 → prefetch_related 사용

🚫 주의할 점

  • select_related는 관계가 복잡하거나 JOIN이 많으면 오히려 성능이 나빠질 수 있음
  • prefetch_related는 메모리를 더 사용하므로, 데이터량이 많다면 주의 필요

📌 참고 예시

queryset = Post.objects.all()
             .select_related('user')         # JOIN 처리
             .prefetch_related('images')     # 별도 쿼리 + 매핑

이렇게 하면, 템플릿에서 다음과 같이 매우 빠르게 접근 가능합니다.

{% for post in object_list %}
  {{ post.user.nickname }}
  {% for image in post.images.all %}
    <img src="{{ image.image.url }}">
  {% endfor %}
{% endfor %}

이처럼 관계에 따라 select_related()와 prefetch_related()를 적절히 사용하면,
쿼리 수를 최소화하고 성능을 극대화할 수 있습니다! 🚀