Django观点,外键领域正在扼杀性能

o4tp2gmn  于 2023-01-21  发布在  Go
关注(0)|答案(1)|浏览(129)

我的对象定义:

class MyObjects(models.Model):
    field_a = models.TextField()
    field_b = models.TextField()
    ...more irrelevant text/int fields
    foreign_key_field = models.ForeignKey(AnotherModel, null=True, on_delete=models.SET_NULL)

视图定义:

@api_view(["GET"])
@permission_classes([IsAuthenticated])
def my_endpoint(request):
    objs = MyObjects.objects.filter(is_active=True)

    ...irrelevant logic

    
    my_dict = defaultdict(int)
    for my_obj in objs:
        ...bunch of irrelevant logic
        my_dict[str(my_obj.foreign_key_field)] += 1
        ...bunch of irrelevant logic

   return Response(my_dict, status=status.HTTP_200_OK)

我在视图中做了一些不相关的计算,如果my_dict[str(my_obj.foreign_key_field)] += 1被注解掉,我的视图大约需要3秒来计算5000个对象。我的视图需要20秒。2这一定是因为这个字段是一个外键字段,而我的其他字段都不是外键。3那一行是引用那个字段的唯一一行。我怎样才能提高这方面的性能呢?我很惊讶仅仅添加这一行就降低了我的性能,因为对象只有大约5k,而外键表大约有50个对象。
因为这一行,没有其他操作会触及这个字典,所以这不是级联效应。如果我注解掉除这一行之外的所有逻辑

@api_view(["GET"])
@permission_classes([IsAuthenticated])
def my_endpoint(request):
    objs = MyObjects.objects.filter(is_active=True)

    my_dict = defaultdict(int)
    for my_obj in objs:
        my_dict[str(my_obj.foreign_key_field)] += 1
   return Response(my_dict, status=status.HTTP_200_OK)

表演还是很糟糕。2有什么改进的办法吗?

jv4diomz

jv4diomz1#

您可以通过以下步骤之一来优化查询:

1.使用select_related减少数据库查询的数量

objs = MyObjects.objects.filter(is_active=True).select_related('foreign_key_field')

2.使用prefetch_related来减少数据库查询次数

objs = MyObjects.objects.filter(is_active=True).prefetch_related('foreign_key_field')

3.使用注解对单个查询中的对象进行计数

objs = MyObjects.objects.filter(is_active=True).annotate(count=Count('foreign_key_field'))

然后

my_dict = {str(obj.foreign_key): obj.count for obj in objs} 
return Response(my_dict, status=status.HTTP_200_OK)

相关问题