최적화_필요하지 않은 것을 검색하지 않기

김동완·2022년 4월 23일
0

DB

목록 보기
13/16
post-thumbnail

필요하지 않은 것을 검색하지 않기

  • 필요하지 않은 것들을 검색하지 않고 필요한 부분들만 검색하자!!

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 문은 쿼리셋을 평가한다 -> 캐시가 생김 
if like_set :
    #쿼리셋은 전체 결과가 필요하지 않은 상황임에도 불구하고 ORM은 전체 결과를 가져온다. 
    #이럴때는 exist가 훨씬 효과적이다. 
    article.like_users.remove(request.user)
  • exists()는 쿼리셋 캐시를 만들지 않으면서 특정 레코드가 존재하는지 검사
  • 결과 전체가 필요하지 않은 경우 유용
like_set = article.like_users.filter(pk = request.user.pk)
#exists() 는 쿼리셋 캐시를 만들지 않으면서 레코드가 존재하는지 검사
if like_set.exists() :
    #DB에서 가져온 레코드가 하나도 없다면
    #트래픽과 메모리를 절약할 수 있다.
    article.like_users.remove(request.user)
  • if문 안에 반복이 있다면, 순회할 때는 if문에서 캐시된 쿼리셋이 사용됨
like_set article.like_users.filter(pk=request.user.pk)

#if문에서 캐시됨 
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 쿼리가 중복될 수 있음
profile
내가 공부한 내용들이 누군가에게 도움이 될지 몰라서 쓰는 벨로그

0개의 댓글