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

在Django文档中,


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


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


“在python中进行连接”是什么意思?有人可以举例说明吗?


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


慕码人2483693
浏览 1723回答 3
3回答

繁星点点滴滴

两种方法可以达到相同的目的,从而放弃不必要的数据库查询。但是他们使用不同的方法来提高效率。使用这两种方法的唯一原因是,当单个大型查询优于许多小型查询时。Django使用大型查询来抢先在内存中创建模型,而不是针对数据库执行按需查询。select_related对每个查找执行联接,但将选择范围扩展为包括所有联接表的列。但是,这种方法有一个警告。联接有可能使查询中的行数相乘。当您通过外键或一对一字段执行联接时,行数不会增加。但是,多对多联接没有此保证。因此,Django限制select_related了不会意外导致大规模联接的关系。对于“ join in python”来说prefetch_related,应该比它还要令人震惊。它为要连接的每个表创建一个单独的查询。它使用WHERE IN子句过滤每个表,例如:SELECT "credential"."id",       "credential"."uuid",       "credential"."identity_id"FROM   "credential"WHERE  "credential"."identity_id" IN    (84706, 48746, 871441, 84713, 76492, 84621, 51472);将每个表拆分为一个单独的查询,而不是执行可能包含太多行的单个联接。

慕妹3146593

我会对您关于预取相关的评论“通常没有多大意义”提出异议。对于标记为唯一的FK字段,这是正确的,但是在多行具有相同FK值(作者,用户,类别,城市等)的任何地方,预取会减少Django和DB之间的带宽,但不会重复行。通常,它在数据库上使用的内存也较少。这些通常比单个额外查询的开销更为重要。鉴于这是一个相当普遍的问题的最佳答案,我认为应该在答案中注明。
打开App,查看更多内容
随时随地看视频慕课网APP