尽管 `select_related` 但 Django 许多外国 table 查询

Django many foreign table queries despite `select_related`

我正在尝试加入 Django 中的 A parent 和 2 child table。

我可以看到每次列表视图 运行 时,都会在 ChildB table 上执行 50 个查询(页面大小)。我以为我可以使用 select_related 方法提高性能,但似乎没有考虑到。

使用 prefetch_related 行为符合预期。

为什么 select_related 没有被考虑在内?

型号:

class Parent(models.Model):
    id = models.AutoField(primary_key=True)
    uuid_a = models.ForeignKey(ChildA, db_column='uuid_a', db_index=True, default=None, editable=False, null=True,
                               on_delete=models.DO_NOTHING, primary_key=False, related_name='result_suppliers', unique=True,)
    uuid_b = models.ForeignKey(ChildB, db_column='uuid_b', db_index=True, default=None, editable=False,
                               null=True, on_delete=models.DO_NOTHING, primary_key=False, related_name='duns_suppliers', unique=True,)


class ChildA(models.Model):
    # ss
    uuid = models.CharField(primary_key=True, editable=False, max_length=36, db_index=True)


class ChildB(models.Model):
    # sd
    id = models.AutoField(primary_key=True, editable=False)
    duns_num = models.ForeignKey(ChildX, db_column='duns_num', to_field='duns_num', db_constraint=False, default=None, editable=False, null=True, on_delete=models.DO_NOTHING, primary_key=False, unique=False)

序列化程序:


class ChildAListSerializer(serializers.ModelSerializer):

    class Meta:
        model = ChildA
        fields = ['uuid', ]  # others


class ChildAListSerializer(serializers.ModelSerializer):

    class Meta:
        model = ChildB
        fields = ['uuid', 'duns_num']  # others


class ParentListSerializer(serializers.Serializer):
    uuid_a = ChildAListSerializer()
    uuid_b = ChildBListSerializer()
    last_sync = serializers.DateTimeField()
    # others

    class Meta:
        model = Parent
        fields = '__all__'

查看:

class ParentListView(ListAPIView):
    """
    List view for deduplication suppliers screen
    """
    filter_backends = [filters.DjangoFilterBackend]
    filterset_class = DeduplicationParentFilter
    pagination_class = LimitOffsetPagination
    page_size = 30
    max_page_size = 30

    pk_field = 'id'  # Name of the primaryKey to use for counting
    fk_fields = ['uuid_a', 'uuid_b']  # Name of the foreignKey to prefetch on request
    model = Parent
    serializer_class = ParentListSerializer

    def get_queryset(self):
        return Parent.objects.select_related(*self.fk_fields)

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        result = {}
    
        # Paginate response
        page = self.paginate_queryset(queryset)

        if page is not None:
            # We can paginate, serialize page
            serializer = self.get_serializer(page, many=True)
            result['data'] = serializer.data
            response = self.get_paginated_response(result)

        else:
            # We cant, serializer queryset
            serializer = self.get_serializer(queryset, many=True)
            result['data'] = serializer.data
            response = JsonResponse(result)
        return response

您的 ChildB 模型中有一个外键导致额外的查询,因为您在该模型序列化程序中使用了它。您需要将其添加到 fk_fields。您可以像使用普通 orm 查询一样使用 __ 来跟踪关系。

fk_fields = ['uuid_a', 'uuid_b', 'uuid_b__duns_num']