Dev./Django & DRF

Django: select_related, prefetch_related, only & defer

Ivan'show 2023. 11. 10.
728x90
반응형

면접 때 나왔었던 질문:

Have you ever used "the prefetch_related or select_related" function in order to optimize DB access ??

 

https://docs.djangoproject.com/en/4.2/ref/models/querysets/#django.db.models.query.QuerySet.select_related

 

Django

The web framework for perfectionists with deadlines.

docs.djangoproject.com

 

select_related()

foreignKey 나 OneToOneField 와 같은 단일 관계 필드에서 사용된다.

JOIN 연산을 이용하여 연관된 객체를 미리 가져온다 → related_name

# Without select_related
for book in Book.objects.all():
    print(book.author.name)

# With select_related
for book in Book.objects.select_related('author'):
    print(book.author.name)
# Hits the database.
e = Entry.objects.get(id=5)

# Hits the database again to get the related Blog object.
b = e.blog

###

# Hits the database.
e = Entry.objects.select_related("blog").get(id=5)

# Doesn't hit the database, because e.blog has been prepopulated
# in the previous query.
b = e.blog
from django.utils import timezone

# Find all the blogs with entries scheduled to be published in the future.
blogs = set()

for e in Entry.objects.filter(pub_date__gt=timezone.now()).select_related("blog"):
    # Without select_related(), this would make a database query for each
    # loop iteration in order to fetch the related blog for each entry.
    blogs.add(e.blog)
from django.db import models

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.

관계가 설정되어 있으면 따로 데이터베이스 연결없이 가져올 수 있다는게 좋은 것 같다.

prefetch_related

ManyToManyField 나 ForeignKey 로 정의된 다대일 관계에 적용된다.

별도의 쿼리를 실행하여 연관된 객체들을 미리 캐싱한다.

# Without prefetch_related
for author in Author.objects.all():
    for book in author.books.all():
        print(book.title)

# With prefetch_related
for author in Author.objects.prefetch_related('books'):
    for book in author.books.all():
        print(book.title)

only & defer

only 는 지정된 필드만 불러오고 defer 는 지정된 필드를 제외한 나머지를 불러온다.

가져오는 데이터 전송을 최소화 하여 성능을 향상시킨다.

# Using only
for book in Book.objects.only('title'):
    print(book.title)

# Using defer
for book in Book.objects.defer('title'):
    print(book.author)

 

 

728x90
반응형

댓글