기술블로그-Django편

📌 Django에서 prefetch_related 완전 정복하기 (쿼리 최소화)

Chansman 2025. 5. 9. 17:10

📌 Django에서 prefetch_related 완전 정복하기


✅ 시작 질문: 이 코드 도대체 왜 쓰는 거야?

queryset = Blog.objects.all().prefetch_related('comment_set', 'comment_set__author')

사용자가 궁금했던 핵심:

이 코드는 뭔가 복잡한 것 같은데, 꼭 써야 해요?
왜 prefetch_related()를 쓰는 건지, 실질적으로 어떤 차이가 나는지 모르겠어요.


1️⃣ prefetch_related란?

Django ORM에서 prefetch_related()는 N+1 쿼리 문제를 막기 위한 최적화 도구입니다.

🔍 N+1 문제란?

  • 블로그 10개를 불러온 후, 각 블로그의 댓글을 따로따로 불러오면:
    → 총 1 + 10 = 11번의 쿼리가 날아감
  • 거기에 댓글 작성자까지 불러오면?
    → 댓글 수만큼 추가 쿼리 발생 → 수십~수백 개 쿼리 😱

2️⃣ prefetch_related 사용 시 쿼리 흐름

queryset = Blog.objects.all().prefetch_related('comment_set', 'comment_set__author')
  • 1번 쿼리: Blog 전체 가져오기
  • 2번 쿼리: 모든 블로그의 댓글(comment_set) 가져오기
  • 3번 쿼리: 모든 댓글의 작성자(author) 가져오기

✅ 총 3번의 쿼리로 끝남 → 훨씬 효율적!


3️⃣ 코드 설명 하나씩 뜯어보기

Blog.objects.all()

→ 블로그 전체 조회

.prefetch_related('comment_set')

→ 블로그별로 연결된 댓글을 미리 한 번에 가져오기

.prefetch_related('comment_set__author')

→ 각 댓글마다 연결된 작성자(author)도 같이 가져오기

💡 이렇게 하면 템플릿이나 뷰에서 접근할 때 추가 쿼리가 발생하지 않음!


✅ 예시 흐름 비교

❌ prefetch_related 안 쓴 경우

for blog in Blog.objects.all():
    for comment in blog.comment_set.all():
        print(comment.author.username)

→ 블로그 10개 + 댓글 50개 → 수십 번 쿼리 발생 ⚠️

✅ prefetch_related 쓴 경우

for blog in Blog.objects.all().prefetch_related('comment_set', 'comment_set__author'):
    for comment in blog.comment_set.all():
        print(comment.author.username)

→ 쿼리 3번으로 끝! ⚡


📌 결론 요약

항목 내용

목적 연관된 객체(댓글, 작성자)를 미리 가져와서 DB 효율 향상
결과 쿼리 수 감소, 성능 개선, 속도 향상
언제 사용? ForeignKey, OneToMany 관계에서 .all(), .filter() 등 루프 돌릴 때

💬 한 줄 정리

prefetch_related()는 "미리 다 끌어와서 캐시해두고, 쿼리 최소화하는 비밀 병기"입니다 💪