43

这是来自查询集方法的django 文档iterator()

QuerySet 通常在内部缓存其结果,以便重复评估不会导致额外的查询。相比之下,iterator() 将直接读取结果,而无需在 QuerySet 级别进行任何缓存(在内部,默认迭代器调用 iterator() 并缓存返回值)。对于返回大量只需要访问一次的对象的 QuerySet,这可以带来更好的性能并显着减少内存。

读完后,我仍然感到困惑:关于提高性能和减少内存的那一行表明我们应该只使用该iterator()方法。有人可以举一些好的和坏的案例iterator()用法的例子吗?

即使查询结果没有被缓存,如果他们真的想多次访问模型,有人不能做以下事情吗?

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

2 回答 2

43

请注意您调用的句子的第一部分: 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 个结果的切片
  • QuerySets 是惰性的,因此您可以拥有一个上下文处理器,例如,它将 QuerySet 放入每个请求的上下文中,但仅在您在某些请求上访问它时才被评估,但如果您强制评估数据库命中发生在每个请求

典型的 Web 应用案例是针对相对较小的结果集(它们必须及时传递到浏览器,因此如果需要,可以使用分页或类似技术来减少数据量),因此通常标准QuerySet行为是您想要的. 毫无疑问,您必须将 QuerySet 存储在一个变量中才能获得缓存的好处。

善用迭代器:处理占用大量可用内存的结果(很多小对象或较少的大对象)。以我的经验,这通常是在进行大量数据处理时的管理命令中。

于 2012-10-02T09:59:42.130 回答
6

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

  • “它需要更多的输入,而不仅仅是 saved_queries = Model.objects.all()”。是的,但有一个主要区别为什么你应该使用 list(Model.objects.all())。让我举个例子,如果你把赋值给一个变量,它将执行查询并将其保存在那里,假设你有 +1M 记录,这意味着你将在一个列表中有 +1M 记录你可能会或可能不会立即使用,所以我建议只使用史蒂文所说的,只使用Model.objects.all(),因为它分配给一个变量,它不会在你调用变量之前执行,从而节省你的数据库来电。

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

于 2018-03-02T15:34:05.830 回答