Когда использовать или не использовать итератор() в 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, чтобы помочь вам и сэкономить массу времени.