TIL96. select_related , prefetch_related
select_related와 prefetch_related란?
select_related와 prefetch_related는 하나의 Queryset을 가져올 때, 미리 related objects들까지 다 불러와주는 함수이다.
비록 query를 복잡하게 만들지만, 불러온 데이터는 모두 cache에 남아있게 되므로 DB에 다시 접근해야 하는 이슈가 줄어들 수 있다.
2가지는 모두 DB에 접근하는 수를 줄여준다.
일명 쿼리 다이어트!!
select_related와 prefetch_related의 차이
select_related
- 정참조(M:1) 혹은 1:1 관계에서 사용이 가능하다.
- 데이터가 많든 적든 JOIN을 통해 한 번의 쿼리문으로 모든 것을 가져온다.
- 쿼리를 한번 호출 하는 것은 효율적이지만 데이터가 많을 때는 응답속도가 느려질 수 있다.
prefetch_related
- 다대다(M:M), 역참조일 때 사용이 가능하나 one-to-one, Foreign key 등 모든 relationship에서도 사용 가능하다.
- JOIN을 하지 않고 개별 쿼리를 실행한 후, django에서 직접 데이터 조합을 합니다.(쿼리 2회이상 실시)
Dog.objects.all() # Dog테이블 1번, Dog를 소유하고 있는 User마다 DB 방문 // 쿼리 폭탄😭
Dog.objects.select_related('User') # inner join쿼리 수행 // 쿼리 1번 수행
Dog.objects.prefetch_related('User') # Dog조회, User조회 // 쿼리 2번 수행
Dog.objects.all() # Dog테이블 1번, Dog를 소유하고 있는 User마다 DB 방문 // 쿼리 폭탄😭
Dog.objects.select_related('User') # inner join쿼리 수행 // 쿼리 1번 수행
Dog.objects.prefetch_related('User') # Dog조회, User조회 // 쿼리 2번 수행
prefetch_related(),select_related() 괄호안에 들어가는건 ()만 사용할거야!
라고 해석하면 쉬울 듯 하다.
사용할 테이블만 갖고오거나 join하기!!
>>> Notification.objects.prefetch_related('company').filter(id=2)
<QuerySet [<Notification: Notification object (2)>]> -- 정참조
>>> Notification.objects.prefetch_related('image_set').filter(id=2)
<QuerySet [<Notification: Notification object (2)>]> -- 역참조 _set붙히기
>>> Notification.objects.prefetch_related('tag').filter(tag__id=2)
<QuerySet [<Notification: Notification object (2)>, <Notification: Notification object (7)>, <Notification: Notification object (12)>, <Notification: Notification object (17)>, <Notification: Notification object (22)>, <Notification: Notification object (27)>, <Notification: Notification object (32)>
--MTM 관계
쿼리 호출 횟수 체감 해보기
MyUser.objects.all()을 사용하면 쿼리는 총 몇번 호출 될까?
정답은 총 4번 이다.
MyUser 모델의 data를 가져오는 쿼리 1개
MyUser 모델에서 가져온 3개의 data에 OneToOne으로 연결된 Company 모델을 가져오는 쿼리 3개
이번에는 MyUser.objects.select_related('company').all()를 사용하여 Company 모델들까지 모두 가져와보겠다!
이번에 쿼리 호출 횟수는 1번이다!
만약, MyUser에 100개의 company와 OneToOne 관계를 가지고 있는 100명의 User가 있다면
MyUser.objects.all()을 사용할 때 101번의 쿼리를 MyUser.objects.select_related('company').all() 로 단 1개의 쿼리로 모든 데이터를 가져올 수 있다.
동일한 조건의 DB에서 MyUser.objects.prefetch_related('company').all()로 쿼리셋을 가져와 보면
이번에는 2개의 쿼리가 실행되었다.
Author And Source
이 문제에 관하여(TIL96. select_related , prefetch_related), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@dnjs0718/selectrelated-prefetchrelated저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)