필요하지 않은 것을 검색하지 않기
- 필요하지 않은 것들을 검색하지 않고 필요한 부분들만 검색하자!!
Don't retrieve things you don't need
- .count()
- 카운트만 원하는 경우
- len(queryset) 대신 QuerySet.count() 사용하기
- .exists()
- 최소한 하나의 결과가 존재하는지 확인하려는 경우
- if queryset 대신 QuerySet.exists()를 사용하는 것이 더 효과적이다.
좋아요 코드 예시
- if 때문에 퀴레섯이 '평가' 되고, 이에 따라 쿼리셋 캐시에도 전체 레코드가 저장
like_set = article.like_users.filter(pk=request.user.pk)
if like_set :
article.like_users.remove(request.user)
- exists()는 쿼리셋 캐시를 만들지 않으면서 특정 레코드가 존재하는지 검사
- 결과 전체가 필요하지 않은 경우 유용
like_set = article.like_users.filter(pk = request.user.pk)
if like_set.exists() :
article.like_users.remove(request.user)
- if문 안에 반복이 있다면, 순회할 때는 if문에서 캐시된 쿼리셋이 사용됨
like_set article.like_users.filter(pk=request.user.pk)
if like_set :
for user in like_set :
print(user.username)
- 여기서 쿼리셋이 엄청 크다면 쿼리셋 캐시 자체가 문제가 될 수 있음
iterator()
- iterator는 객체가 많을 때 쿼리셋의 캐싱 동작으로 인해 많은 양의 메모리가 사용될 때 사용
- 몇 천개 단위의 레코드를 다뤄야 할 경우, 이 데이터를 한 번에 가져와 메모리에 올리는 행위는 매우 비효율적이기 때문
- 데이터를 작은 덩어리로 쪼개어 가져오고, 이미 사용한 레코드는 메모리에서 지움
like_set = article.like_users.filter(pk=request.user.pk)
if like_set :
for user in like_set.iterator() :
print(user.username)
- 그런데 쿼리셋이 엄청 큰 경우 if문도 문제가 될 수 있다.
like_set = article.like_users.filter(pk = request.user.pk)
if like_set.exist() :
for user in like_set.iterator() :
print(user.username)
안일한 최적화 주의
- exitst()와 iterator() 메서드를 사용하면 메모리 사용을 최적화 할 수 있지만, 쿼리셋 캐시는 생성되지 않기 때문에, DB 쿼리가 중복될 수 있음