Django ORM 中的 select_related 和 prefetch_related 有什么区别?

新手上路,请多包涵

在 Django 文档中,

select_related() “遵循”外键关系,在执行查询时选择其他相关对象数据。

prefetch_related() 对每个关系进行单独查找,并在 Python 中进行“连接”。

“在 python 中加入”是什么意思?有人可以举例说明吗?

我的理解是,对于外键关系,使用 select_related ;对于 M2M 关系,使用 prefetch_related 。这个对吗?

原文由 NeoWang 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 562
2 个回答

你的理解大部分是正确的。当您要选择的对象是单个对象时,您使用 select_related ,因此 OneToOneFieldForeignKey 。你使用 prefetch_related 当你要得到一组“东西”时,所以 ManyToManyField 如你所说或相反 ForeignKey 只是为了澄清我所说的“反向 ForeignKey s”的意思,这是一个例子:

 class ModelA(models.Model):
    pass

class ModelB(models.Model):
    a = ForeignKey(ModelA)

ModelB.objects.select_related('a').all() # Forward ForeignKey relationship
ModelA.objects.prefetch_related('modelb_set').all() # Reverse ForeignKey relationship

不同之处在于 select_related 执行 SQL 连接,因此将结果作为表的一部分从 SQL 服务器返回。 prefetch_related 另一方面执行另一个查询,因此减少了原始对象中的冗余列(上例中的 ModelA )。您可以将 prefetch_related 用于任何您可以使用 select_related 的东西。

权衡是 prefetch_related 必须创建 ID 列表并将其发送回服务器,这可能需要一段时间。我不确定在交易中是否有这样做的好方法,但我的理解是 Django 总是只发送一个列表并说 SELECT … WHERE pk IN (…,…,…)基本上。在这种情况下,如果预取数据是稀疏的(假设美国国家对象链接到人们的地址)这可能非常好,但是如果它更接近一对一,这可能会浪费大量通信。如果有疑问,请尝试两者,看看哪个表现更好。

上面讨论的一切基本上都是关于与数据库的通信。然而,在 Python 方面 prefetch_related 具有额外的好处,即单个对象用于表示数据库中的每个对象。使用 select_related 将在 Python 中为每个“父”对象创建重复对象。由于 Python 中的对象有相当多的内存开销,这也是一个考虑因素。

原文由 CrazyCasta 发布,翻译遵循 CC BY-SA 4.0 许可协议

这两种方法实现相同的目的,放弃不必要的数据库查询。但是他们使用不同的方法来提高效率。

使用这两种方法中的任何一种的唯一原因是当单个大型查询比许多小型查询更可取时。 Django 使用大查询抢占式地在内存中创建模型,而不是对数据库执行按需查询。

select_related 对每个查找执行连接,但扩展选择以包括所有连接表的列。然而,这种方法有一个警告。

联接有可能使查询中的行数成倍增加。当您对外键或一对一字段执行联接时,行数不会增加。但是,多对多连接没有此保证。因此,Django 将 select_related 限制为不会意外导致大量连接的关系。

prefetch_related“加入 python” 比它应该的更令人担忧。它为每个要连接的表创建一个单独的查询。它使用 WHERE IN 子句过滤每个表,例如:

 SELECT "credential"."id",
       "credential"."uuid",
       "credential"."identity_id"
FROM   "credential"
WHERE  "credential"."identity_id" IN
    (84706, 48746, 871441, 84713, 76492, 84621, 51472);

不是执行可能有太多行的单个连接,而是将每个表拆分为一个单独的查询。

原文由 cdosborn 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题