Django ORM 설명: selected_related 및 prefetch_related
성능 문제의 예
이 모델의 예를 들어보겠습니다.
from django.db import models
class User(models.Model):
name = models.CharField(max_length=50)
email = models.EmailField(max_length=254)
class Profile(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
first_name = models.CharField(max_length=50)
엄청난! 여기에는 두 가지 모델이 있으며
Profile
모델은 ForeignKey
모델과 User
-- 일대다 -- 관계가 있습니다. 즉, 사용자가 많은 프로필을 가질 수 있습니다.프로필 개체가 있는 경우 사용자를 얻는 기본 방법은 무엇입니까?
# hit the database
profile = Profile.objects.first()
# hit the database again to get the related User object
user = profile.user
글쎄, 우리는 여기서 두 가지 쿼리를 만들었습니다. 그다지 큰 문제는 아니지만 이러한 라인을 최적화하고 불필요한 쿼리를 피하고자 합니다.
관련 항목 선택
Django docs ,
select_related()
에서 쿼리를 실행할 때 추가 관련 개체 데이터를 선택하여 외래 키 관계를 "따르는"QuerySet을 반환합니다. 이것은 하나의 더 복잡한 쿼리를 생성하는 성능 부스터이지만 나중에 외래 키 관계를 사용할 때 데이터베이스 쿼리가 필요하지 않음을 의미합니다.기본적으로 선택하려는 개체가 단일 개체일 때
select_related
를 사용하므로 OneToOneField
또는 ForeignKey
입니다.user
개체가 있는 profile
를 가져오는 줄을 다시 작성해 보겠습니다.# Hits the database
profile = Profile.objects.select_related('user').first()
# Doesn't hit the database, because profile.user has been prepopulated
# in the previous query.
user = profile.user
그리고 방금 두 개의 쿼리를 하나로 변환했습니다. 그러나
ManyToMany
관계가 있거나 ManyToOne
만 있으면 어떻게 됩니까?사용자 개체가 있는 모든 프로필을 가져와야 하는 경우를 살펴보겠습니다.
프리페치 관련
User 모델에 str 메서드를 추가해 봅시다.
class User(models.Model):
name = models.CharField(max_length=50)
email = models.EmailField(max_length=254)
password = models.CharField(max_length=50)
def __str__(self) -> str:
return "%s (%s)" % (self.name,
", ".join(profile.first_name for profile in self.profile_set.all()))
Note: If you are using a
ForeignKey
relationship in Django between an M1 model and an M2 model -- which is symmetrical by default --, the M1 model has automatically a reverse relationship field of typeManyToOne
.
다음 코드를 실행하면 다음과 같은 결과가 나타납니다.
>>> User.objects.all() [<User: User (John Doe)>, <User: User (Jane Doe)> ...]
이 쿼리의 문제점은 User 모델의__str__
메서드가 호출될 때마다 데이터베이스에서self.profile_set.all()
를 쿼리해야 한다는 것입니다.
그리고 쿼리 수는 사용자의 프로필 수에 비례합니다. 음, 악몽입니다.🥶
하지만 어떻게 이것을 단 두 개의 쿼리로 줄일 수 있을까요? 음,prefetch_related
를 사용합니다.
User.objects.prefetch_related('profile_set').all()
prefetch_related
사물의 "세트"를 얻을 때 사용하므로ManyToMany
또는 반대 방향으로ForeignKey
--ManyToOne
.
그렇다면 둘의 차이점은 무엇입니까?
둘 다 데이터베이스에서 데이터를 미리 가져오는 동일한 원칙에 따라 작동하지만 서로 다른 접근 방식을 사용합니다.
아래에 이미 언급했지만 이 내용에 대한 결론을 내리자.선택하려는 개체가 단일 개체일 때 select_related
를 사용하므로OneToOneField
또는ForeignKey
입니다.prefetch_related
는 사물의 "세트"를 가져올 때 사용하므로ManyToMany
또는 반대 방향으로ForeignKey
--ManyToOne
.
그러나 데이터베이스 쿼리 수를 줄이고 데이터베이스에서 더 큰 크기의 데이터를 가져오는 데 문제가 없는 경우 이러한 방법을 사용해야 합니다.
내 경험상 이러한 방법은 Django에서 배고픈 크론 작업을 실행하는 데 정말 도움이 되었습니다.🤟
Django 애플리케이션에서 더 적은 수의 데이터베이스 쿼리를 만들기 위해 사용하는 다른 방법은 무엇입니까? 의견 섹션에서 논의합시다.
bloggu.io을(를) 사용하여 게시된 기사. 무료로 사용해 보세요.
Reference
이 문제에 관하여(Django ORM 설명: selected_related 및 prefetch_related), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/koladev/django-orm-explained-selectedrelated-and-prefetchrelated-27a7텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)