[Django] ORM 최적화

그냥·2022년 7월 8일
0

django

목록 보기
17/20

1. Lazy Loading

ORM

  • 정의: 필요한 QuerySet 혹은 구문을 저장해놓고 DB 요청이 필요한 시점에만 요청을 보내는 것
  • Query문 실행 횟수: 위와 같이 ORM을 실행했을 때 DB에 Query문은 0번 실행된다.
  • DB에 요청을 보내는 시점: QuerySet Evaluation이 되는 시점은 Slicing, Iteration, repr(), len(), list(), bool() ... 등이다. 이때만 DB에 요청을 보냄
  • 성능 저하: Lazy Loading에서는 성능 저하 이슈는 거의 없음


2. Caching

  • 정의: 메모리에 작업을 올려 놓는 것
  • Query문 실행 횟수: 1번
  • DB에 요청을 보내는 시점: list() 사용시
  • 성능 저하: Caching을 하면 통신 효율성 증가

캐시 저장

캐시 저장 x

  • _result_cache: 쿼리셋 캐시에 저장되어 있는 값을 불러오는 메서드
  • queryset[0]으로 했을 때 쿼리셋 캐시에 저장하지 않는다.

캐시 저장 o

  • for문으로 사용할 때는 쿼리셋 평가를 하면서 캐시에 저장된다.
  • 통신 효율을 줄일 수 있다.


3-1. N+1 Problems(정참조)

  • 정의: N+1 Problem이란 캐싱 데이터에 저장되어 있는 값이 없을 때 다시 DB에 직접 통신을 해서 계속 가져와야 한다.

  • book.pubilsher.name: book.publisher.name 처럼 한 테이블에서 다른 테이블을 참조를 할 경우 통신 효율성이 매우 떨어지게 된다.

  • latency가 발생하는 이유: for book in querset을 할 때 book에 대한 정보가 캐싱되지만, book.publisher.name을 불러올 때는 캐싱 데이터가 정보가 없어서 계속해서 DB에 요청을 해야하기 때문이다.

  • latency: 클라이언트 요청이 들어왔을 때 응답까지의 시간. 보통 0.4~0.7초에 반환되어야 좋은 API이다.

  • 해결방법: 한 번에 데이터를 가져와서 캐시에 저장한다.
    - Queryset = Book.obejects.all().select_related("publisher")

    	select_related()란 한 객체에서 다른 객체를 참조한 것을 합쳐서 객체를 만들어 주는 ORM이다.


3-2 N+1 Problems(역참조)

  • store.books.all()에서 데이터를 가져올 때 문제 발생

  • 해결 방법: prefetch_related()를 사용해서 역참조를 하는 테이블 합친다.
  • 목적: 한 번에 가져와서 통신을 하자
  • 쿼리 실행 횟수: 2번
    - Store 1번
    - books 1번
  • 차이점:
    • select_related(): sql단에서 join문을 써서 정참조 한 값을 더해서 테이블을 하나로 가져온다.
    • prefetch_related(): sql단에서 역참조 한 값을 합쳐서 가져 오지 않고, 추가로 query를 가져와서 장고단에서 붙이는 것이다.


3-3 N+1 Problems(역참조)

  • 상황: prefetch_related()를 썼지만 filter() ORM을 사용함. 이럴 경우 캐시 데이터를 사용해서 DB와의 통신이 없을 것 같지만 filter 때문에 DB와의 통신이 발생한다.

  • 해결방법: prefetch_related() 안에 Prefetch() 객체를 만든다. 그리고 그 안에 가져올 테이블의 이름, queryset, to_attr=이름 을 작성한다.
to_attr: queryset이 다른 조인 쿼리에도 사용된다면 해당 쿼리가 실행될 때마다 새로 조회를 하므로 중복조회가 발생됩니다. 
이때, prefetch()에서 제공하는 to_attr을 사용하여 쿼리를 메모리에 저장하여 효율적으로 사용할 수 있습니다.
  • 쿼리 실행 횟수: 3번
    • prefetch_related: 1번
    • Book.objects.all(): 1번
    • filter(name='Book9991'): 1번


0개의 댓글

관련 채용 정보