TIL51 | Django ORM 최적화(Lazy Loading, Caching, N+1 Problems)
2021. 11. 18. 08:35ㆍ언어/Python
반응형
Lazy Loading(지연 로딩)
필요할 때만 함수를 호출하는 개념
- 파이썬에서는 generator 함수
- Django에서는 QuerySetAPI에서 지연로딩 특징을 가지고 있다.
# DB 호출되지 않음.
queryset = Publisher.objects.filter(id=20).exclude(id=2).annotate(count=Count('book'))
함수를 호출할 때 DB쪽에 실행되는 것이 아니라, queryset이 평가 될 때 DB를 호출한다.
QuerySet이 평가 될 때 == 실제로 db를 호출하는 시점
Slicing, Iteration, repr()
queryset = Publisher.objects.filter(id=20).exclude(id=2).annotate(count=Count('book'))
# Lazy Loading시 쿼리는 어디에 저장되어 있는가?
print("queryset.query에 저장된 SQL문 :: ", queryset.query)
QuerySet으로 반환하는 함수들을 실행할 때 queryset.query 변수에 Sql문이 저장된다.
Caching
지연로딩이 가지는 문제
같은 값을 가져오더라도 요청할 때마다 통신해야한다.
# 각각 select문으로 호출 (3번 호출)
queryset[0]
queryset[0]
queryset[0]
해결 방법
QuerySet이 가지는 caching 기능으로 위 문제를 해결할 수 있다.
result_cache에 db에서 가져온 값을 저장해둔다.
(caching을 하는 경우 : list, for문)
# 단 1번 select문으로 호출
list(queryset) ---> queryset.result_cache에 sql문으로 가져온 값들을 저장해둔다.
queryset[0]
queryset[0]
queryset[0]
N + 1 Problems
API 설계 방식 (Architecture)
- REST
- 엔드포인트가 여러개
- 엔드포인트가 정의된 대로만 줄 수 있음
- resource별로 http method로 uri를 설계하는 것
- GrapQL
- 엔드포인트 1개
- 모든 요청을 한군데로 보낸다
- Front에서 Back에 Sql문처럼 uri 요청을 보낸다.
select_related
queryset.query : 하나의 쿼리에 계속 더해진다.
prefetch_related
queryset.query에는 하나의 root query만.
queryset._prefetch_related_lookups : 추가 쿼리 개념. 기존 쿼리보내고, 추가적으로 다음 쿼리 보낸다.
prefetch_related('my_tables')는 전체 데이터를 가져와서 caching해두는 것이기 때문에,
역참조할 모델에 filter를 걸어야하는 경우 모든 데이터마다 where 조건을 걸어서 쿼리를 날리게 된다.
이런 문제를 해결하기 위해 Prefetch 객체를 사용할 수 있다.
total_books = [book.name for book in store.books.all()]
filtered_books = [book.name for book in store.books.filter(name='Book9991')]
queryset = Store.objects.prefetch_related(
Prefetch('books', queryset=Book.objects.all(), to_attr='total_books'),
Prefetch('books', queryset=Book.objects.filter(name='book999'), to_attr='filterd_books'),
)
Prefetch 객체
- 역참조 할때 filter 조건을 걸어야하는 경우에 사용
Load test
npm install loadtest
- API 성능 테스트
반응형
'언어 > Python' 카테고리의 다른 글
TIL47 | Django Exceptions (0) | 2021.11.10 |
---|---|
TIL46 | Query Performance Counter Decorator (0) | 2021.11.10 |
TIL45 | QuerySetAPI - select_related & prefetch_related (0) | 2021.11.10 |
TIL42 | Python에서 CSV파일 다루기(db_uploader.py) (0) | 2021.11.05 |
TIL41 | CodeKata 복소수 계산, 리스트 뒤집기 (0) | 2021.11.02 |