Отсутствие сериализации поля внешнего ключа для ускорения производительности - PullRequest
2 голосов
/ 04 июня 2019

Представьте, что у меня есть следующие модели (не обращайте внимания на типы полей, пример назначения):

class County(model.Model):
   country = models.TextField()

class City(model.Model):
   country = models.ForeignKey(Country)
   city    = models.TextField()

class Person(model.Model):
   city = models.ForeignKey(City)
   name = models.TextField()

и соответствующие сериализации этих моделей

class CountrySerializer(serializers.HyperlinkedModelSerializer):
   class Meta:
      model  = Country
      fields = ('country')

class CitySerializer(serializers.HyperlinkedModelSerializer):
   country = CountrySerializer()

   class Meta:
      model  = City
      fields = ('city', 'country')

class PersonSerializer(serializers.HyperlinkedModelSerializer):
   city = CitySerializer()

   class Meta:
      model  = Person
      fields = ('name', 'city')

Хорошо, поэтому я использую Django REST Framework для создания API. Одна из конечных точек - /person, которая возвращает всех людей.

def get(request):
   persons = Person.objects.all()
   data = PersonSerializer(persons, many = True)
   return JsonResponse(data.data, safe = False) 

Дело в том, что сериализация persons занимает так много времени из-за ForeignKey s.

Моя главная цель - как можно быстрее выполнить запрос, настраивая этот код, модели или сериализаторы.

Простой [1], но, очевидно, не самый лучший способ - хранить фактические строки city и country внутри модели Person и только сериализовать их, поэтому фактические внешние ключи используются только для Запросы и фильтрация. Но в этом случае масштабирование этого кода будет ужасным (?).

Я также пытался использовать индексы, но улучшение было не тем, что я искал.

Есть предложения или рекомендации?

В моем реальном случае у меня есть модель "Person" с 4 различными моделями внешних ключей (одна из которых имеет модель внешнего ключа внутри) и разницей во времени между естественным и лоскутным способом [1] составляет ~7 s против ~1 ms соответственно (что я считаю огромным улучшением).

подробности:

  • Прибл. 1000 " лиц " и 500 за объекты " внешних ключей " в моей базе данных.
  • Я также использую базу данных кеша, поэтому последующие запросы не так уж плохи (более или менее 25% от первоначальных), но первый - ужасен ...

Настройки:

  • Джанго: 1.11
  • Python: 3.6

1 Ответ

2 голосов
/ 04 июня 2019

Довольно реальная проблема (ха-ха). При таком простом поиске вы получите:

  • 1 вызов базы данных для извлечения всех Person объектов (поиск .all)

В сериализаторе вы получите:

  • Для каждого человека 1 вызов базы данных, чтобы получить его city
    • Для каждого города, который вы выбираете, добавьте 1 вызов базы данных, чтобы получить этот город country

Вы можете уменьшить это с помощью select_related:

Person.objects.select_related('city', 'city__country')

Вы также можете использовать поиск values, чтобы захватывать только те поля, которые вы хотите, и обрабатывать полученный плоский словарь в своем представлении или в SerializerMethodField. Как объединить select_related () и value ()? (2016)

...