[django] 효율적으로 데이터 가져오기 ft.select_related, prefetch_related

이승연·2020년 12월 30일
0

DJango

목록 보기
4/11
post-thumbnail

백엔드 개발자는 데이터 보호와 서버의 부하를 생각하며 로직을 짜야한다. 단순로직만 짜는게 아니라굿.

프리패치 임포트해오기 : from django.db.models import Prefetch
부하 테스팅하는 법 : npm install node test

Book이 Publisher를 정참조하고 있는 경우를 생각해보자

비효율적인 방법: 다 가져와버리기

queryset = Book.objects.all()
  • for문을 사용해 각 데이터에 접근한다. Publisher는 book.publisher.name으로 접근하는데 캐싱되지 않은 데이터이므로 query가 발생한다. 아주아주 많은 query가...... 당연히 시간도 많이 걸린다. (쿼리: 9000번) (걸린 시간: 2분)

효율적인 방법: 캐싱해서 가져와버리기

queryset = Book.objetcs.select_related("publisher").all()
  • 이번에는 select_related를 이용해서 publisher의 데이터를 캐싱해놓은 상태! Book테이블에 존재하는 publisher의 정보만 캐싱하기 때문에 훨씬 더 효율적이다. (쿼리: 3번) (걸린 시간: 짱 짧음)
  • prefetch_related를 써도 되지만 거의 큰 차이가 없다고 한다...

Store가 Book을 역참조하고 있는 경우를 생각해보자

비효율적인 방법: 다 가져와버리기

queryset = Store.objects.all()

효율적인 방법: 캐싱해서 가져와버리기

상황1: 다 필요할 때?

queryset = Store.objects.prefetch_related("books").all()
  • 쿼리 두개: store가져온 다음에 book가져옴 , storebooks에서 필요한 것들만 가져옴

상황2: 필터를 추가해야할 때?

queryset = Store.objects.prefetch_related("books").all()
  • 가져온 쿼리셋 중 필터를 추가해야하는 경우가 있다. 그럴 땐 store.books.filter(name='Book1')처럼 가져오는 방법이 있다. - 캐싱을 했다고 해도 필터를 추가했기 때문에 데이터베이스를 다시 hit해야한다... 비효율적
queryset = Store.objects.prefetch_related(Prefetch('books', queryset = Book.objects.filter(name='Book1'))
  • 처음부터 가져올때 prefetch객체 안에 조건을 충족하는 것만 가져와서 캐싱하는 방법!
  • store.books.all()만 쓰면 모든게 나에게로 온다 ㅎㅎㅎ (쿼리: 4번) (걸린 시간: 0.03초)

상황3: 내가 가져온 쿼리셋에 이름을 붙여주자

queryset = Store.objects.prefetch_related(Prefetch('books', queryset = Book.objects.filter(name='Book1'), to_attr='book1_list'))
  • store.book1_list라고 부르면 모든게 나에게로 온다

0개의 댓글