느린 직렬화(Serialization) 과정 최적화하기

직렬화 과정의 병목을 찾아내고 해결하는 최적화 기법들로, 데이터베이스 쿼리는 빠르지만 JSON 변환 과정에서 발생하는 성능 저하를 해결

N+1 쿼리 해결

문제: 관련 객체 접근 시 매번 추가 쿼리 발생

  • Post 목록에서 각각의 author.username 접근 시 N+1 문제 발생

해결: select_relatedprefetch_related 활용

  • select_related: ForeignKey, OneToOneField 관계 (JOIN 사용)

  • prefetch_related: 역방향 ForeignKey, ManyToManyField 관계

# 개선 전
queryset = Post.objects.all()  # N+1 발생

# 개선 후  
queryset = Post.objects.select_related('author').all()  # 2번 쿼리로 해결

SerializerMethodField 최적화

문제: 커스텀 필드에서 매번 무거운 연산 실행

해결책 1: DB 레벨에서 미리 계산 (annotate)

# View에서 미리 계산
queryset = Post.objects.annotate(likes_count=Count('likes'))

# Serializer에서 일반 필드로 사용
likes_count = serializers.IntegerField(read_only=True)

해결책 2: 인스턴스 레벨 캐싱

def get_complex_data(self, obj):
    if hasattr(obj, '_complex_data'):
        return obj._complex_data
    
    result = self._calculate_complex_data(obj)
    setattr(obj, '_complex_data', result)
    return result

목록/상세 Serializer 분리

목적: 목록 API에서 불필요한 데이터 제거로 응답 속도 향상

class PostListSerializer(serializers.ModelSerializer):
    # 목록에 필요한 최소 필드만
    class Meta:
        fields = ['id', 'title', 'author_username']

class PostDetailSerializer(serializers.ModelSerializer):
    # 상세 정보 포함
    class Meta:
        fields = ['id', 'title', 'content', 'author', 'tags', 'files']

# ViewSet에서 action별 Serializer 분리
def get_serializer_class(self):
    if self.action == 'list':
        return PostListSerializer
    return PostDetailSerializer

values()를 이용한 초고속 직렬화

목적: 대용량 데이터의 읽기 전용 API에서 극한 성능 필요 시

장점: 모델 인스턴스화 오버헤드 제거로 월등한 속도 단점: ModelSerializer 편의기능 사용 불가, 유지보수 어려움

# 기본 Serializer 사용
class UltraFastPostSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    title = serializers.CharField()
    author__username = serializers.CharField()

# values()로 dict 형태 데이터 추출
queryset = Post.objects.select_related('author').values(
    'id', 'title', 'author__username'
)

최적화 우선순위

  1. select_related/prefetch_related: 모든 직렬화의 기본, N+1 의심 시 최우선 적용

  2. annotate: 집계/통계 데이터 필요 시

  3. Serializer 분리: 목록과 상세의 필요 데이터가 다를 때

  4. values() + Serializer: 대용량 읽기 전용 API에서 극한 성능 필요 시

Last updated