Django View, поле внешнего ключа убивает производительность

Определение MyObjects:

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)

Я делаю некоторые вычисления в моем представлении, которые не имеют значения, и мое представление занимает около 3 секунд для 5000 объектов, если my_dict[str(my_obj.foreign_key_field)] += 1 закомментировано. Однако, когда эта строка не закомментирована, мое представление занимает 20 секунд. Это должно быть потому, что это поле является полем внешнего ключа, так как ни одно из моих других полей не является внешним ключом. Эта конкретная строка - единственная строка, ссылающаяся на это поле. Как я могу улучшить производительность? Я удивлен, что просто добавление этой строки снижает производительность на столько, так как объектов всего около 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)

производительность по-прежнему ужасна. Есть идеи, как улучшить?

вы можете оптимизировать запрос одним из следующих шагов:

1. Используйте select_related для уменьшения количества запросов к базе данных

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

2. Используйте prefetch_related для уменьшения количества запросов к базе данных

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

3. Используйте annotate для подсчета объектов в одном запросе

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

then

my_dict = {str(obj.foreign_key): obj.count for obj in objs} 
return Response(my_dict, status=status.HTTP_200_OK)
Вернуться на верх