하기에 작성된 글의 출처는 장고 공식문서입니다
select_related
와 prefetch_related
의 정의와
사용했을 때 어떻게 돌아가는 지 설명 후, 해당 내용을 예시로 한 코드를 작성했습니다.
이번 원티드 프리온보딩 과정을 하며 처음으로 사용해보게 되어서
아직 문법에 서툴지만, 점차 익숙해져서 능숙하게 사용할 수 있을거라 생각합니다.
OneToOneField
나 ForeignKey
관계에서 사용할 수 있으며,
OneToOneField
의 경우 역참조에 사용 가능합니다.
즉, 정참조에는 ForeignKey
를, 역참조에는 OneToOneField
를 사용합니다.
단, OneToOneField
의 경우 특정 컬럼명을 명시해야 하며, models.py
에서
related_name
을 사용해야 한다고 합니다.
select_related
는 내가 가져올 모델과 *fields
안의 테이블 or 테이블의 컬럼을
JOIN
하여 교집합인 부분을 가져옵니다.
만약 select_related
를 여러번 쓰고 싶다면, 두 가지 방법으로 표기 가능합니다.
1. select_related('class1', 'class2')
2. select_related('class1').select_related('class2')
예를 들어
class Author(models.Model) :
name = models.CharField(...)
...
class Meta :
db_table = 'authors'
class Book(...) :
author = models.ForeignKey(Author, ...)
...
class Meta :
db_table = 'books'
위와 같이 모델링을 하고 사용한다면
# DB hit 1번
b = Book.objects.select_related('author').get(id=1)
# DB hit X (이미 위에서 author의 정보를 불러왔으므로 hit하지 않음)
c = b.author
이와 같이, Book
모델에 한 번 접근을 하면 되는 것입니다.
select_related
로 JOIN
을 통해 관계된 정보를 불러왔기 때문입니다.
정참조관계에 있는ManyToManyField
나 ManyToOneField
에서 사용되고,
역참조관계에 있는 ForeignKey
관계에서 사용됩니다.
장고 공식문서에는 GenericRelation
, GenericForeignKey
도
지원한다고 나와있는데, 이건 추후에 공부하며 포스팅할 예정입니다.
JOIN
하여 데이터를 가져오는 select_related
와 달리,
prefetch_related
는 *look_ups
로 지정된 모델을 불러오는 쿼리를
한 번 더 실행합니다.
prefetch_related
의 경우, 'joining' in Python
이라는 문구로 설명하고 있는데,
상위 모델에서 쿼리를 1차로 실행하고, 상위 모델에서 받아온 ID를 통해
prefetch
할 모델에 접근하여 두 번째 쿼리를 실행합니다.
예를 들어 아래와 같이 모델링을 한 뒤,
class Topping(...) :
name = models.CharField(...)
class Meta :
db_table = 'toppings'
class Pizza(...) :
name = ...
toppings = models.ManyToManyField(Topping)
class Meta :
db_table = 'pizzas'
피자는 토핑을 정참조하고 있습니다.
그러면 토핑에게 피자는 역참조 관계입니다.
select_related
를 통해 피자마다 토핑이 어떻게 들어있는지 접근하려면
pizza = Pizza.objects.select_related('topping')
으로 코드를 작성하면 됩니다.
만약 코드 작성을 이렇게 한다면
toppings = Topping.objects.prefetch_related('pizza_set').get(id=1)
토핑 테이블에서 id가 1인 정보를 가져온 뒤,
pizza로 접근하여 1번 토핑을 사용하는 피자가 어떤 게 있는지 접근할 수 있게 됩니다.
처음 사용해봐서 그런지 정말 세밀하게 까진 아직 감이 안옵니다.
계속 써보면서 Django ORM 최적화를 할 수 있는 개발자가 되어야 할 것 같습니다.