TIL #40 select_related & prefetch_related

데이터베이스의 데이터를 가져오기 위해 query을 수행하는데, 초소한의 query로 최대한의 퍼포먼스(데이터베이스의 접근을 줄이고 처리 속도를 증가)를 내기 위해 select_relatedprefetch_related을 사용한다.

이 둘은 최초 query를 통해 관련 데이터를 캐쉬에 저장하고, 필요한 데이터를 데이터베이스에서 가져다 쓴다는 공통점이 있지만, query 수행에 방식이나 용도에는 조금의 차이가 있다.

1. select_related

  • 정참조 관계에서 사용
  • JOIN을 사용하여 query 수행
  • select_related 사용 전
    - 코드
    -query=> SELECT query가 계속해서 수행되고 있다.

  • select_related 사용 후
    - 코드=> 정참조 관계인 'series'와 'color__filtering_color'의 데이터들 같이 가져온다.
    - query=> 한 번의 SELECT query 후 더 이상 query을 진행 하지 않는다.

2. prefetch_related

  • 역참조, many to many, many to one 관계에서 쓰인다.
  • select_related와는 다르르게 JOIN이 아닌 역참조 관계에서 별도의 2개의 query 수행 후 파이썬에서 join 한다.
  • prefetch_related 예제
    => Category와 역참조 관계인 drink을 prefetch_related로 불러 오게 되면 category와 drink 각 각의 query가 수행 되는 것을 볼 수 있다.
    => prefetch_related로 query 수행 후 캐쉬에 저장 된 데이터를 사용해 별로의 query 수행 없이 data을 가져오는 것 을 볼 수 있다.

3. 주의 사항

Note

Remember that, as always with QuerySets, any subsequent chained methods which imply a different database query will ignore previously cached results, and retrieve data using a fresh database query. So, if you write the following:

>pizzas = Pizza.objects.prefetch_related('toppings')
>[list(pizza.toppings.filter(spicy=True)) for pizza in pizzas]

…then the fact that pizza.toppings.all() has been prefetched will not help you. The prefetch_related('toppings') implied pizza.toppings.all(), but pizza.toppings.filter() is a new and different query. The prefetched cache can’t help here; in fact it hurts performance, since you have done a database query that you haven’t used. So use this feature with caution!

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

요약: prefetch_related로 topping을 불러 왔어도 .filter는 다른 query을 수행하기 때문에 오히려 prefetch을 사용하는 것이 더 비효율적일 수 있다.

좋은 웹페이지 즐겨찾기