[Django] select_related(), prefetch_related()

김가람휘·2022년 3월 9일
0

Django

목록 보기
12/13

django.db.models.query.py

class QuerySet:
    """Represent a lazy database lookup for a set of objects."""

    def __init__(self, model=None, query=None, using=None, hints=None):
        self.model = model
        self._db = using
        self._hints = hints or {}
        self.query = query or sql.Query(self.model)
        self._result_cache = None
        self._sticky_filter = False
        self._for_write = False
        self._prefetch_related_lookups = ()
        self._prefetch_done = False
        self._known_related_objects = {}  # {rel_field: {pk: rel_obj}}
        self._iterable_class = ModelIterable
        self._fields = None
  • query: 1개의 메인 쿼리로 부를 수 있다.
  • result_cache: SQL의 수행 결과가 저장되는 부분(캐싱), 저장된 데이터가 없을 경우 새로운 SQL문 호출한다.
  • prefetch_related_lookups: prefetch_related()부분에 선언된 값들을 저장한다, 추가 쿼리셋이라고 부른다.
  • iterable_class: SQL의 결과값을 python의 어떤 자료구조로 받을 지에 대한 부분, values(), values_list()를 통해 바뀐다.

  • 하나의 쿼리셋을 가져올 때 연관되어 있는 objects들을 미리 불러오게(Eager Loading)하는 함수이다.
  • JOIN문을 사용하기 때문에 호출되는 SQL문이 복잡해질 수 있지만, 이렇게 불러온 데이터들은 result_cache라는 부분에 cache되기 때문에 결과적으로 중복 호출을 방지할 수 있다.
  • 이렇게 두 함수 모두 DB에 액세스(connection)하는 횟수를 줄여주므로 Performance를 향상시킬 수 있다.

  • select_related()는 JOIN을 통해 데이터를 즉시 가져오는(Eager Loading)방법 -> SQL단계에서의 JOIN(1번의 hit)
  • prefetch_related()는 추가 쿼리를 통해 데이터를 즉시 가져오는 방법 -> 추가 쿼리 발생, JOIN은 파이썬 level에서 이루어진다.(2번의 hit)
  • 따라서 이 두 함수의 차이는 추가쿼리가 발생하느냐 아니냐로 구분지을 수 있다.
    -> 1:1 관계에서 무조건 Inner Join으로 한번만 가져오는 select_related를 사용하는 것이 좋을까? 그건 아니다.
    -> ORM조건이 복잡하거나 데이터 양이 방대한 경우에는 한 번에 Query를 전부 조회해서 가져오는 것보다 prefetch_related를 이용하여 두번으로 나눠 각각 가져오는 것이 속도면에서 더 빠를 수도 있다.

  • 1:1의 관계에서 사용할 수 있고, 1:N의 관계에서 N이 사용할 수 있다.
  • 즉, 정방향 참조에서의 JOIN에 유리하게 사용된다.

  • 1:N의 관계에서 1이 사용할 수 있고, M:N의 관계에서 사용할 수 있다.
  • 즉, 역방향 참조에 유리하게 사용된다.

0개의 댓글