Json.dumps требует слишком много времени для преобразования данных

Я использую json.dumps для создания некоторых отчетов из моей модели Django.

    start = time.process_time()
    items = Allotment.objects.all().order_by('dispatch_date')
    print("allotments", len(items))
    serializer = AReportSerializer(items, many=True)
    items_json = json.dumps(serializer.data)
    print("allot time", time.process_time() - start)

Я проверил время запроса и сериализации, и оно слишком мало, чтобы даже заметить, но json.dumps занимает слишком много времени, иногда оно исчисляется минутами. Что я должен сделать, чтобы уменьшить это время обработки?

Вы не измеряете время, которое занимает json.dumps(). Вы измеряете время для

  • база данных и Django ORM
  • принятие AReportSerializer для формирования данных (что происходит при доступе к serializer.data)
  • собственно сериализация JSON.
start = time.process_time()
items = Allotment.objects.all().order_by("dispatch_date")
print("allotments", len(items))
print("query time", time.process_time() - start)
serializer = AReportSerializer(items, many=True)
data = serializer.data
print("data time", time.process_time() - start)
items_json = json.dumps(data)
print("json time", time.process_time() - start)

там было бы ближе к истине.

В любом случае, если даже этот бенчмарк докажет, что json.dumps не спешит, библиотека orjson станет более быстрой заменой для json...

QuerySet'ы в Django являются ленивыми. Это означает, что при построении кверисета он не будет делать запрос для получения результатов. По сути, это класс, который обещает сделать вызов базы данных, когда вам нужны эти элементы. Например, когда вы перечисляете элементы, определяете их длину и т.д. Таким образом, это означает, что только когда вы вызовете len(items) здесь, он выполнит фактический запрос.

То же самое происходит при сериализации. Сериализатор обещает сгенерировать ответ для .data, но он не будет делать это немедленно, когда вы конструируете сериализатор. Пока это может быть сделано, когда вам это действительно нужно, этого достаточно.

Более того, сериализаторы могут создавать проблему N+1, когда вы сериализуете данные, которые хранятся в объекте, связанном с внешним ключом объекта, который вы визуализируете. В этом случае Django делает не один запрос, а N+1 запросов с N количеством Allotment. Первый запрос извлекает все Allotments, а затем идут N запросов для извлечения связанного объекта из базы данных. Вы можете работать с .select_related(…) [Django-doc] и .prefetch_related(…) [Django-doc] для получения данных в одном запросе, или с одним дополнительным запросом. Таким образом, вы должны посмотреть, какие типы объектов модели все извлекаются для создания данных serializer.data.

После оптимизации кода, он все равно может привести к большой задержке, если количество Allotment записей начнет расти. В этом случае целесообразно пагинирование контента. Это защищает сервер от неэффективной работы, если определенное количество посетителей захотят получить все Allotment в одном запросе.

Вернуться на верх