Select_related 와 prefetch_related

Sang Jun Lee·2020년 7월 26일
0

select_related와 prefetch_related의 차이

select_related는 SQL의 join을 사용하는 특성에 따라 foreign-key, one-to-one과 같은 single-value 관계에서만 사용이 가능하다는 한계가 있습니다.
반면 prefetch_related는 many-to-many등 모든 관계에서 사용이 가능합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
from django.db import models
 
 
class Country(models.Model):
 
    name = models.CharField(
        max_length=10,
    )
 
    def __str__(self):
        return self.name
 
 
class Person(models.Model):
 
    city = models.ForeignKey(City)
     
    name = models.CharField(
        max_length=10,
    )
 
    def __str__(self):
        return self.name
         
         
class Pet(models.Model):
 
    person = models.ForeignKey(Person)
     
    name = models.CharField(
        max_length=10,
    )
 
    def __str__(self):
        return self.name

------------------------------------

# Not use select_related()
 
pet = Pet.objects.get(id=1)
person = pet.person
country = person.country

----------------------------------------

# Use select_related()
 
pet = Pet.objects.select_related('person__country').get(id=1)
person = pet.person
country = person.country


출처: https://jupiny.tistory.com/entry/selectrelated와-prefetchrelated [jupiny의 개발일지]

출력결과로는 selet_related를 쓴 것과 안 쓴 것의 차이가 없지만 데이터베이스에 접근하는 방식을 보면 차이가 납니다.

첫번째 방식은 데이터베이스에 총 3번 접근을 합니다. 그러나 select_related방식은 미리 정보를 가져와 캐쉬에 저장하여 사용함으로 데이터베이스에 다시 접근하지 않습니다.

다대다 관계를 추가하여 prefetch에 대해 설명해보겠습니다.

class Language(models.Model):
 
    person_set = models.ManyToManyField(Person)
 
    name = models.CharField(
        max_length=10,
    )
 
    def __str__(self):
        return self.name


출처: https://jupiny.tistory.com/entry/selectrelated와-prefetchrelated [jupiny의 개발일지]

데이터베이스에서 person의 모든 인스턴스와 그 인스턴스의 언어셋을 모두 출력해야한다고 가정해서 설명하도록 하겠습니다.
Tom: Python Ruby
Peter: Python Node.js Java
John: Java C++ php

# No use prefetch_related()
 
people = Person.objects.all()
for person in people:
    print(person.name+" : ", end="")
    for language in person.language_set.all():
        print(language.name+" ", end="")
    print("")

--------------------------------------------------

# Use prefetch_related()
 
people = Person.objects.all().prefetch_related('language_set')
for person in people:
    print(person.name+" : ", end="")
    for language in person.language_set.all():
        print(language.name+" ", end="")
    print("")

출처: https://jupiny.tistory.com/entry/selectrelated와-prefetchrelated [jupiny의 개발일지]

이번에도 사용했을때와 안했을때를 보겠습니다.
첫번째의 경우 person이 100명 있다면 데이터베이스에 100번 요청을 한다는 의미가 되지만 두번째의 경우는 미리 가져와서 캐쉬에 담아놓고 불러오기에 효율적인 요청이 이뤄진다고 보면 되겠습니다.

profile
Live now and Dream better tomorrow

0개의 댓글