Django - select_related() & prefetch_related()

폐쇄맨·2020년 11월 17일
0

select_related()

장고는 select_related()라는 QuerySet 메서드를 제공한다. 이는 one-to-many 관계의 객체를 검색할 때 사용한다. 이는 복잡한 QuerySet이 될 수 있지만, 연관 관계에 있는 필드에 접근하기 위해 추가적인 쿼리를 날릴 필요가 없게된다. select_related() 메서드는 ForeignKeyOneToOne 필드에 사용한다. SQL의 JOIN 쿼리를 통해 연관 객체를 가져오게 된다.

class City(models.Model):
    # ...
    pass

class Person(models.Model):
    # ...
    hometown = models.ForeignKey(
        City,
        on_delete=models.SET_NULL,
        blank=True,
        null=True,
    )

class Book(models.Model):
    # ...
    author = models.ForeignKey(Person, on_delete=models.CASCADE)
    
# Hits the database with joins to the author and hometown tables.
b = Book.objects.select_related('author__hometown').get(id=4)
p = b.author         # Doesn't hit the database.
c = p.hometown       # Doesn't hit the database.

# Without select_related()...
b = Book.objects.get(id=4)  # Hits the database.
p = b.author         # Hits the database.
c = p.hometown       # Hits the database.

만약 argument 없이 select_related()를 호출하면, 모든 ForeignKey 관계의 객체를 검색할 것이다. 그렇기 때문에, 항상 호출 이후에 접근할 관계에 대해서만 select_related()를 사용해야한다.

select_related()를 사용하는 것은 실행 시간을 굉장히 증가시킬 수 있기 때문에 조심해서 사용해야한다.

prefetch_related()

select_related()가 one-to-many 관계의 연관 객체들을 검색하는데 도움을 준다. 하지만 select_related()는 many-to-many 또는 many-to-one 관계 (ManyToMany 또는 역(逆)ForeignKey 필드)에 대해서는 소용이 없다. 장고는 prefetch_related() 메서드를 제공한다. prefetch_related()는 각 관계에 대해서 lookup을 나눠서하고, 파이썬을 이용해서 결과를 합친다. 이 메소드는 GenericRelationGenericForeignKey에 대한 prefetching도 지원한다.

class Topping(models.Model):
    name = models.CharField(max_length=30)

class Pizza(models.Model):
    name = models.CharField(max_length=50)
    toppings = models.ManyToManyField(Topping)
    
class Restaurant(models.Model):
    pizzas = models.ManyToManyField(Pizza, related_name='restaurants')
    best_pizza = models.ForeignKey(Pizza, related_name='championed_by', on_delete=models.CASCADE)
    
>>> Restaurant.objects.prefetch_related('pizzas__toppings')
# This will result in a total of 3 database queries - one for the restaurants, one for the pizzas, and one for the toppings.
>>> Restaurant.objects.prefetch_related('best_pizza__toppings')
# 2 queries using select_related()
>>> Restaurant.objects.select_related('best_pizza').prefetch_related('best_pizza__toppings')
profile
폐쇄맨

0개의 댓글