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

2025. 5. 14. 23:23·기술블로그-Django편

🔍 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()를 적절히 사용하면,
쿼리 수를 최소화하고 성능을 극대화할 수 있습니다! 🚀

'기술블로그-Django편' 카테고리의 다른 글

🧠 Django 클래스 기반 뷰(CBV)의 속성들, 왜 쓰는지 헷갈린다면?  (0) 2025.05.15
🔍 Django에서 'results = ...' 와 {'results': results}가 왜 둘 다 나오나요?  (0) 2025.05.15
📂 Django에서 MEDIA_URL과 MEDIA_ROOT 설정 완벽 이해하기  (0) 2025.05.14
✅ Django에서 User 모델을 참조하는 두 가지 방식 비교  (0) 2025.05.14
📂 Django 모델에서 str() 함수 작동 흐름 완벽 해설  (0) 2025.05.14
'기술블로그-Django편' 카테고리의 다른 글
  • 🧠 Django 클래스 기반 뷰(CBV)의 속성들, 왜 쓰는지 헷갈린다면?
  • 🔍 Django에서 'results = ...' 와 {'results': results}가 왜 둘 다 나오나요?
  • 📂 Django에서 MEDIA_URL과 MEDIA_ROOT 설정 완벽 이해하기
  • ✅ Django에서 User 모델을 참조하는 두 가지 방식 비교
Chansman
Chansman
안녕하세요! 코딩을 시작한 지 얼마 되지 않은 초보 개발자 찬스맨입니다. 이 블로그는 제 학습 기록을 남기고, 다양한 코딩 실습을 통해 성장하는 과정을 공유하려고 합니다. 초보자의 눈높이에 맞춘 실습과 팁, 그리고 개발하면서 겪은 어려움과 해결 과정을 솔직하게 풀어내려 합니다. 함께 성장하는 개발자 커뮤니티가 되기를 바랍니다.
  • Chansman
    찬스맨의 프로그래밍 스토리
    Chansman
  • 전체
    오늘
    어제
    • 분류 전체보기 (787)
      • Python (32)
      • 프로젝트 (110)
      • 과제 (25)
      • Database (40)
      • 멘토링 (11)
      • 특강 (37)
      • 기술블로그 (41)
      • 기술블로그-Fastapi편 (33)
      • 기술블로그-Django편 (153)
      • 기술블로그-Flask편 (36)
      • AI 분석 (5)
      • HTML & CSS (31)
      • JavaScript (17)
      • AWS_Cloud (21)
      • 웹스크래핑과 데이터 수집 (14)
      • Flask (42)
      • Django (77)
      • Fastapi (16)
      • 연예 (14)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    btscomeback
    life reflection
    smartphonedurability
    livebroadcast
    travel ban
    global politics
    youngprofessionals
    RM
    gpterror
    college reunions
    btsreunion
    self-growth
    americaparty
    chatgpterror
    remittance
    classaction
    homebartrend
    btsdischarge
    뷔
    chinanightlife
    urbantrends
    americanlaw
    hotcoffeecase
    bts
    trumpmuskclash
    btsjungkook
    titaniumcase
    basalcellcarcinoma
    newpoliticalparty
    lawsuitculture
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
Chansman
🔍 Django ORM 쿼리 최적화 - select_related vs prefetch_related
상단으로

티스토리툴바