ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 속도 개선을 하기 위해서 알아야 할 필수적인 것.! SubQuery
    IT 2024. 8. 8. 18:00

    모델과 모델 사이에 관계가 없을 때, 

    class CommonCompanySerializer(serializers.ModelSerializer):
        """Company Serializer

        Serializer of Company table by ModelSerializer

        Attributes:
            Meta.model (ModelBase): Company
            Meta.fields (str): company and business_name column of Company
        """
        timezone_abbrev = serializers.SerializerMethodField()

        class Meta:
            model = models.Company
            fields = (
                'company', 'business_name', 'category',
                'address_01', 'city', 'state', 'zip', 'timezone_abbrev',
            )

        def get_timezone_abbrev(self, obj):
            if isinstance(obj, dict):
                timezone_name = obj.get('timezone')
            else:
                timezone_name = obj.timezone

            timezone = models.TimeZone.objects.filter(name=timezone_name).first()
            return timezone.abbrev if timezone else timezone_name


    다음과 같이 serializer에서 진행을 하게 되면, GET method로 list를 불러오면 한개의 row마다 query 하나씩 발생하게 되어서 속도 저하의 원인이 되게 됩니다.

    원래는 timezone을 사용했지만, timezone_abbrev 정보도 가져오고 싶어서 TIMEZONE TABLE에서 가져오려는데, COMPANY와 RELATED가 되어 있지 않아서, 문제가 발생하는 것이예요.

    가장 쉬운 방법은 TIMEZONE TABLE을 가져와서 DICT으로 만들어서 FOR문에서 찾기 하면 QUERY는 날라가지 않겠지만 내부적으로 오래걸리게 되죠 COST 냠냠

    그래서 이러한 상황에서는 SUBQUERY를 사용하자아~

     

    class CommonCompanySerializer(serializers.ModelSerializer):
        """Company Serializer

        Serializer of Company table by ModelSerializer

        Attributes:
            Meta.model (ModelBase): Company
            Meta.fields (str): company and business_name column of Company
        """
        timezone_abbr = serializers.CharField()

        class Meta:
            model = models.Company
            fields = (
                'company', 'business_name', 'category',
                'address_01', 'city', 'state', 'zip', 'timezone_abbr'
            )

    SERIALIZER 파일에서는 계산에 대한 코드를 지우고 간단하게 만들어 놓고,

    class CompanyViewSet(viewsets.ReadOnlyModelViewSet):
        """Company R

        UseCases of Company table by ReadOnlyModelViewSet

        Attributes:
            serializer_class (SerializerMetaclass): serializer
            queryset (QuerySet): all of active=True queryset objects
        """

        serializer_class = serializers.CommonCompanySerializer
     
        timezone_subquery = models.TimeZone.objects.filter(
            name=OuterRef('timezone')
        ).values('abbrev')[:1]
        queryset = serializer_class.Meta.model.objects.filter(
            active__exact=True
        ).only(
            'company', 'business_name', 'category', 'address_01', 'city', 'state',
            'zip', 'timezone'
        ).values(
            'company', 'business_name', 'category', 'address_01', 'city', 'state',
            'zip', 'timezone'
        ).annotate(
            timezone_abbr=Subquery(timezone_subquery)
        )
        lookup_url_kwarg = 'keyword'

    VIEW SET에서 저렇게 TIMEZONE TABLE에 대한 데이터를 가져오고, ANNOTATE로 SUBQUERY써서 뚜악 하면,

    TIMEZONE, COMPANY에 대한 쿼리 각 한번씩 총 2번으로 해결할 수 있다~

    이전에는 COMPANY가 100개라고 치면, COMPANY 1개 TIMEZONE 100개 해서 101번의 쿼리가 날라가는데 딱 해결.!

    참고로 ONLY(), VALUE()를 사용해도 속도를 줄일 수 있어요. 상황에 따라 다릅니다. PREFETCH()도 있고 암튼
    여기까지

    'IT' 카테고리의 다른 글

    python pdf reportlab과 Blob URL  (4) 2024.08.13
    프로그램이 무겁다?  (0) 2024.08.12
    하나 하나 적어보는 IT 용어  (0) 2024.07.30
Designed by Tistory.