Когда использовать или не использовать итератор() в ORM django

Это из документации django по методу queryset iterator():

QuerySet обычно кэширует свои результаты внутри, чтобы повторные оценки не приводили к дополнительным запросам. Напротив, iterator() будет читать результаты напрямую, без какого-либо кэширования на уровне QuerySet (внутренне, итератор по умолчанию вызывает iterator() и кэширует возвращаемое значение). Для QuerySet, который возвращает большое количество объектов, к которым вам нужно получить доступ только один раз, это может привести к повышению производительности и значительному сокращению памяти.

После прочтения я все еще в замешательстве: строка об увеличении производительности и сокращении памяти говорит о том, что нам следует просто использовать метод iterator(). Может кто-нибудь привести примеры хороших и плохих случаев использования iterator()?

Даже если результаты запроса не кэшируются, если они действительно хотели получить доступ к моделям более одного раза, не может ли кто-то просто сделать следующее?

saved_queries = list(Model.objects.all().iterator())

Ответы

Ответ 1

Обратите внимание на первую часть предложения, которое вы вызываете: For a QuerySet which returns a large number of objects that you only need to access once

Итак, обратное это: если вам нужно повторно использовать набор результатов, и их не так много, чтобы вызвать проблему с памятью, тогда вы не должны использовать iterator. Потому что дополнительная поездка в базу данных всегда будет уменьшать вашу производительность по сравнению с кешированным результатом.

Вы можете заставить свой QuerySet оцениваться в списке, но:

  • для этого требуется больше ввода, чем просто saved_queries = Model.objects.all()
  • скажите, что вы показываете paginating результаты на веб-странице: вы будете вынуждены все результаты в память (обратно к возможным проблемам памяти), а не позволять последующему paginator выбрать срез из 20 результатов, которые ему нужны.
  • QuerySet являются ленивыми, поэтому вы можете иметь обработчик контекста, например, который помещает QuerySet в контекст каждого запроса, но только оценивается, когда вы получить доступ к ним по определенным запросам, но если вы принудительно оценили, что попадание базы данных происходит каждый запрос

Типичный пример веб-приложения - это относительно небольшие результирующие наборы (они должны быть доставлены в браузер своевременно, поэтому для уменьшения объема данных при необходимости используется разбиение на страницы или аналогичный метод), поэтому обычно стандартный QuerySet поведение - это то, что вы хотите. Как вы, несомненно, знаете, вы должны хранить QuerySet в переменной, чтобы получить преимущество от кеширования.

Хорошее использование итератора: обработка результатов, которые занимают большое количество доступной памяти (много мелких объектов или меньше крупных объектов). По моему опыту, это часто происходит в командах управления при большой обработке данных.

Ответ 2

Я согласен со Стивеном и хотел бы провести наблюдение:

  • msgstr "это требует большего набора текста, чем просто сохраненные_запросы = Model.objects.all()". Да, это так, но есть большая разница, почему вы должны использовать список (Model.objcts.all()). Позвольте мне привести вам пример: если вы поместите присвоенный переменной переменный, он выполнит запрос, а затем сохранит его там, представьте, что у вас есть записи +1M, так что это означает, что вы будете иметь записи +1M в список, который вы можете или не можете использовать сразу после, поэтому я бы рекомендовал использовать только, как сказал Стивен, только используя Model.objects.all(), потому что это присвоено переменной, она не будет выполняться, пока вы не вызовете переменную, сохраняя тебе БД звонит.

  • Вы должны использовать prefetch_related(), чтобы уберечь вас от выполнения многих вызовов в БД, и, следовательно, он будет использовать обратный поиск django, чтобы помочь вам и сэкономить массу времени.