djnago Query 최적화 select_related,prefetch_related

김하진·2022년 7월 21일
0

Selected_related 란 ?

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 란?

prefetch_related는 selected_related와 같이 data를 Cache에 저장하며, 모든 relationships에서 사용이 가능하다.

Selected_related  vs  Prefetch_related

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를 이용해야 한다.

내일, 쿼리최적화를 계속해서 진행하면서 테스트 코드도 마저 작성할 예정이다.

profile
진킴

0개의 댓글