Selected_related는 SQL Query 문의 JOIN 을 사용하여 foreign-key(one to one, many to one)를 사용하여 정참조할 때 사용하며 QuerySet을 가져올 때, 미리 related objects까지 불러오는 함수이다.
비록 쿼리는 복잡해지지만 불러온 data들은 데이터베이스 서버가 종료되기 전 까지 Cache에 남게되어 매 쿼리마다 DB에 접근하지 않아도 된다.
def get_rank_list(self, obj):
rank_list_get = UserProfileModel.objects.all().order_by("-mongle_grade")[:10]
rank_list = [
{"user": rank_list.user.username, "profile_img": rank_list.profile_img}
for rank_list in rank_list_get
]
기존 코드인 UserprofileSerializer 이다.
하지만 이 방식보다는, User를 기반으로한 MainPageDataSerialzier 를 만들어서 데이터를 한번에 보내주는게 좋다고 생각해서
다시 코드를 수정하였다.
def get_rank_list(self, obj):
user_profile_get = UserModel.objects.select_related("userprofile").all().order_by('-monglegrade')[:10]
rank_list = [{"username":rank_list.username,"profile_img":rank_list.userprofile.profile_img} for rank_list in user_profile_get]
return rank_list
기존 코드라면,, User모델을 통해서, UserProfile 을 통해서 데이터를 가져와야하지만, selecet.reated 를 통해서 처음부터 가져오면 쿼리개수를 줄일 수 있다. 지금은 간단한 코드이지만, 이런게 수십개가 쌓이다보면 서버가 무거워 지는건 당연한 얘기이다.
또한 편지의 개수를 카운트 하는 부분도
my_worry =WorryBoardModel.objects.select_related("letter").filter(author=request.user)
letter_count = 0
for letter_get in my_worry:
if letter_get.letter.is_read == False:
letter_count += 1
Q를 통해서 카운트를 쿼리하는 것보다, 가져온 데이터를 통해서 카운트를 얻어주는 코드로 변경 하였다.
Q도, 한번에 쿼리를 1개씩 가진다고 한다.
prefetch_related는 selected_related와 같이 data를 Cache에 저장하며, 모든 relationships에서 사용이 가능하다.
Selected_related는 하나의 Query로 related Objects들을 불러오지만, Prefetch_related는 main query가 실행이 된 후 별도의 query가 실행이 된다. 따라서 1번 이상 쿼리가 진행되기 때문에 가급적 selected_related를 사용하는 것이 리소스 소모를 줄일 수 있다, 또한 역참조시 사용이 된다.
woory_list1 = WorryCategory.objects.prefetch_related("worryboard_set").all()
현재 작성중인 쿼리이다.
이 코드는 완성이 되면 다시 작성할 예정이다. wooryboard_set이 역참조라 prefetch_realated를 이용해야 한다.
내일, 쿼리최적화를 계속해서 진행하면서 테스트 코드도 마저 작성할 예정이다.