-
django 에서 select_related, prefetch_related 에서 추가적인 ORM 을 사용하기기술/Django 2021. 9. 24. 19:49
Django 의 ORM 을 사용하면서 select_related, prefetch_related 를 쓸 때
성능상의 이점을 위해 테이블을 복잡하게 다룰 필요가 있을 때가 자주 존재합니다.
그 때 사용하기 유용한 FilteredRelation 과 Prefetch 를 소개하고자 합니다.
FilteredRelation
FilteredRelation 은 Django ORM 에서 JOIN 절에 추가적인 조건을 줄 수 있는 방법입니다.
만약 OUTER JOIN 하는 테이블의 크기가 크다면 FilteredRelation 을 사용하여 성능을 개선할 수 있습니다.
Filter 의 위치 Where vs Join
OUTER JOIN 을 사용할 때 Where 절을 사용한다면 OUTER JOIN 을 완성한 다음 필터링을 합니다. 그렇기 때문에 테이블이 크다면 그 크기를 모두 감당해야합니다.
OUTER JOIN 을 사용할 때 ON 절에서 추가적인 필터를 사용한다면 OUTER JOIN 하는 테이블이 작아져 필터링 된 만큼만 데이터를 가져오면 되는 부분에서 성능 차이가 발생합니다.
# Where 절에서 사용했을 때 # 여기서 불러온 총 Comment 가 100만개 삭제된 Comment 가 80만개라면 # 100만개 데이터를 모두 합친 후 필터링을 수행합니다. Post.objects.filter( comment_set__deleted__isnull=True, ) # JOIN 절에서 사용했을 때 # 여기서는 삭제된 Comment 80만개를 제외한 20만개의 데이터만을 불러온 후 결과를 나타냅니다. Post.objects.annotate( comment_exclude_deleted_set=FilteredRelation( 'comments', condition=Q(deleted__isnull=True), ) )
Prefetch
prefetch_related 로 가져오는 데이터를 좀 더 복잡하게 다루고 싶다면 Prefetch 를 사용합니다.
주의사항으로는 Prefetch 로 가져온 데이터는 Queryset 이 아닌 List 라서, 추가적인 쿼리가 불가합니다.
posts = Post.objects.prefetch_related( Prefetch( 'comments', # 필터 뿐만아니라 QuerySet 에서 Ordering, Annotate 등 더 복잡한 쿼리를 사용해 가져오게 할 수 있습니다. queryset=Comments.objects.filter(deleted__isnull=True), ) )
'기술 > Django' 카테고리의 다른 글
Django 에서 Jupyter Notebook 을 사용할 때 서브 디렉터리를 기본으로 설정하는 방법 (0) 2021.09.24 Traefik vs Caddy (1) 2021.09.24 django-filters 를 사용하여 복잡한 환경에서 OrderingFilter 사용하기 (0) 2021.09.24 Django 에서 일시적으로 auto_now, auto_now_add 를 disable 시키는 법 (0) 2021.09.24 Django Filters 에서 하나의 Key를 가지고 여러 값 필터하기 ( MultipleFilter ) (0) 2021.09.24