🔍 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 |