django ORM 최적화

GisangLee·2023년 10월 31일
0

django orm

목록 보기
2/2

1. django ORM의 특징

Lazy Loading

  • 필요한 시점에 쿼리를 수행한다. (게으르다)
  • users 부분에서는 쿼리를 수행하지 않고
    첫번째 유저를 가져오는 부분과, 전체 유저를 list로 묶는 과정에서 각각 쿼리문이 수행되었다.

caching

  • 위 사진처럼 쿼리가 두번 발생하는 것을 방지하기 위함
  • list로 묶는 과정에서 쿼리가 한 번 수행되고
    첫번째 유저는 캐싱된 데이터에서 추출한다.

Eager Loading > N+1 Problem

쿼리셋은 Lazy Loading으로 동작한다.
하지만 한 번에 많은 데이터를 조회하고 싶을 때가 있는데
이것을 Eager Loading이라고 부르며 이를 지원하기 위해
select_related, prefetch_related 등이 있다.

  • Lazy Loading이기 때문에 반복문 안에서
    동일한 쿼리가 중복으로 발생하여 아래와 같이 N+1 문제가 발생할 수 있다.
  • 유저를 전부 조회하기 위해 쿼리 1번
    각 유저의 관계를 조회하기 위해 반복문만큼 쿼리 수행하여 N+1번 수행하게 된다.

쿼리에 JOIN하여 데이터를 즉시 로딩하는 방식

추가 쿼리를 수행하고 파이썬 레벨에서 JOIN하여 데이터를 즉시 로딩하는 방식


2. 실수하기 쉬운 ORM 쿼리셋

prefetch_related는 다르다.

filter()는 1개의 쿼리에 대해 이뤄진다.
따라서 추가적인 쿼리인 prefetch_related는 filter의 적용을 받지 않는다고 한다.
아래처럼 할 경우, 데이터 조회를 위해 비효율적인 쿼리가 작성된다.

  • filter()안에서INNER JOIN으로 관계형 테이블을 조인한다.

  • 그 이후 prefetch_related로 인해 추가 쿼리가 수행된다.

해결방안 2가지

  1. prefetch_related 제거!
  • INNER JOIN으로 데이터를 가져오도록 한다.
  1. filter안에 있는 관계형 조건을 Prefetch로 이동
  • 이 방법은 user 쿼리에서 INNER JOIN을 하지않고
    추가 쿼리에서 where절이 수정된다.

3. 쿼리셋 작성 순서

Model -> annotate -> select_related -> filter -> prefetch_related

  • filter 앞에 prefetch_related를 두면 위와 같은 현상이 발생할 수 있기 때문에 prefetch_related를 filter 뒤에 두는 것을 추천한다고 한다.
profile
포폴 및 이력서 : https://gisanglee.github.io/web-porfolio/

0개의 댓글