何时在Django ORM中使用或不使用迭代器

2024-04-20 00:28:49 发布

您现在位置:Python中文网/ 问答频道 /正文

这是来自django docs on the queryset ^{} method

A QuerySet typically caches its results internally so that repeated evaluations do not result in additional queries. In contrast, iterator() will read results directly, without doing any caching at the QuerySet level (internally, the default iterator calls iterator() and caches the return value). For a QuerySet which returns a large number of objects that you only need to access once, this can results in better performance and a significant reduction in memory.

在阅读之后,我仍然感到困惑:关于提高性能和减少内存的一行建议我们应该只使用iterator()方法。有人能举例说明好的和坏的用法吗?

即使查询结果没有被缓存,如果他们真的想访问模型不止一次,难道就不能有人这样做吗?

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

Tags: andthedjangoindocsobjectsthaton
2条回答

注意句子的第一部分: For a QuerySet which returns a large number of objects that you only need to access once

因此,相反的是:如果您需要重用一组结果,而这些结果数量不多,以致于导致内存问题,那么您不应该使用iterator。因为额外的数据库往返总是会降低性能,而不是使用缓存的结果。

您可以强制将QuerySet计算到列表中,但是:

  • 它需要更多的输入,而不仅仅是saved_queries = Model.objects.all()
  • 假设您正在对网页上的结果进行分页:您将强制将所有结果放入内存(返回到可能的内存问题),而不是允许后续分页器选择它所需的20个结果片段
  • ^{}s are lazy,因此您可以有一个上下文处理器,例如,它将一个QuerySet放入每个请求的上下文中,但只有在您对某些请求进行访问时才会对其求值,但是如果您强制求值,则每个请求都会发生数据库命中

典型的web应用程序是针对相对较小的结果集的(它们必须及时交付到浏览器,因此如果需要,可以使用分页或类似的技术来减少数据量),因此通常标准的QuerySet行为就是您想要的。如您所知,您必须store the QuerySet in a variable才能从缓存中获益。

迭代器的良好使用:处理占用大量可用内存(大量小对象或更少大对象)的结果。根据我的经验,在处理大量数据时,这通常出现在管理命令中。

我同意史蒂文的观点,我想做一个观察:

  • “它需要更多的输入,而不仅仅是保存的查询=Model.objects.all()。”。是的,但使用list(Model.objcts.all())的原因有很大不同。我给你举个例子,如果你把赋值给一个变量,它将执行查询,并将其保存在那里,假设你有+1M条记录,这意味着,你将有+1M条记录在一个列表中,你可以在之后立即使用,也可以不立即使用,所以我建议你只使用史蒂文所说的方法,仅使用Model.objects.all(),因为这是分配给变量的,所以只有调用该变量才能执行,从而节省了数据库调用。

  • 您应该使用prefetch_related()来避免在数据库中执行许多调用,因此,它将使用django反向查找来帮助您并节省大量时间。

相关问题 更多 >