당신은 쿼리셋에 대해 얼마나 알고 계신가요. 이번 시리즈는 Django 의 Query Api 를 살펴보면서 그동안 내가 놓친 부분은 없었나 혹은 몰랐던 것들을 알아보려고 한다.(기본적인 것도 정리하려고 했으나, 너무 기초적인 거라 빼기로 했다.)
Django 공식 문서를 보고 진행하겠다.
1. Lazy QuerySet
Querysets are lazy! 공식 문서에 표현되어 있다. 이말이 뭔가하니 queryset이 평가되기 전까지는 실제로 데이터베이스를 들르지 않는다.
그렇다면 QuerySet은 언제 평가(evaluated)될까?
1.1 Queryset이 평가되는 경우
1.1.1 반복
Queryset은 반복 가능하며 처음 반복할 때 데이터베이스 쿼리를 실행한다.
for e in Entry.objects.all():
print(e.headline)
주의 ! 적어도 하나의 결과가 존재하는지 확인하는 것이 전부인 경우에는 exists()를 사용하는 것이 더 효율적이다.
exists()는 결과가 포함되어 있으면 True를 반환한다.
비동기도 같다.
async for e in Entry.objects.all():
results.append(e)
1.1.2 슬라이싱
Queyrset은 파이썬 array 슬라이싱 문법으로 슬라이스가 가능하다. 이때 Slicing 할 때는 평가 되지 않지만, "step"을 사용할 경우 평가가 된다. 그리고 이때 list가 반환된다.
1.1.3 Pickling/Caching
Queryset을 pickle 한다면 피클하기 전에 결과를 memory에 적재한다. Queyrset을 Pickle 하면 스냅샷처럼 해당 시점의 DB 결과가 저장 된다.
1.1.4 repr()
repr을 요청할 때 평가된다.인터프리터의 편의를 위한 것이므로, 대화형으로 사용할 때 결과를 확인할 수 있다.
1.1.5 len()
len을 요청하면 평가된다. 결과의 길이를 반환한다.
1.1.6 list()
queryset을 list 형태로 변환하면 평가된다.
entry_list = list(Entry.objects.all())
2. Caching 에 대해 알아보자.
캐싱을 이용해 데이터베이스 액세스를 최소화해보자(결국 이것도 자원이므로). Queryset이 처음으로 평가될 때 DB에 히트된다. Django는 쿼리 결과를 Queryset의 캐시에 저장하고 결과를 반환한다. 따라서 Queryset을 후에 호출하면 캐시된 결과를 사용한다. 하지만 잘못된 사용은 비효율적인 동작을 할 수 있으므로 아래와 같은 예에서 효율적인 사용을 배우자
>>> queryset = Entry.objects.all()
>>> print([p.headline for p in queryset]) # Evaluate the query set.
>>> print([p.pub_date for p in queryset]) # Reuse the cache from the evaluation.
그렇다면 캐시되지 않는 경우도 보자.
>>> queryset = Entry.objects.all()
>>> print(queryset[5]) # Queries the database
>>> print(queryset[5]) # Queries the database again
이와 같이 Queryset의 일부를 가져올 때는 캐싱된 결과를 가져오지 않고 DB를 다시 들른다. 이 말은 배열을 slicing 하여 limited 시키거나 index로 접근 한다면 캐싱하지 못한다는 뜻이다.
그렇다면 올바른 예를 살펴보자
>>> queryset = Entry.objects.all()
>>> [entry for entry in queryset] # Queries the database
>>> print(queryset[5]) # Uses cache
>>> print(queryset[5]) # Uses cache
다음의 예는 전체 쿼리를 캐싱하여 다양하게 쓰일 때의 예이다.
>>> [entry for entry in queryset]
>>> bool(queryset)
>>> entry in queryset
>>> list(queryset)
다음에는 DB의 hit수를 줄일 수 있는 select_related() 와 prefetch_related()에 대해 살펴보겠다.
'Django' 카테고리의 다른 글
[Pytest] - django-dotenv 와 pytest-dotenv 오류 (0) | 2022.12.19 |
---|---|
[DRF] - Serializers Class 알아보기(1) (0) | 2022.12.14 |
[DRF - Django Rest Framework] Serializer Field 톺아보기(3) (0) | 2022.12.13 |
[DRF - Django Rest Framework] Serializer Field 톺아보기(2) (0) | 2022.12.07 |
[DRF - Django Rest Framework] Serializer Field 톺아보기(1) (0) | 2022.11.30 |