Django ORM 中的 select_related 和 prefetch_related 有什么区别? [英] What's the difference between select_related and prefetch_related in Django ORM?

查看:24
本文介绍了Django ORM 中的 select_related 和 prefetch_related 有什么区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 Django 文档中,

In Django doc,

select_related() 跟随"外键关系,在执行查询时选择额外的相关对象数据.

select_related() "follows" foreign-key relationships, selecting additional related-object data when it executes its query.

prefetch_related() 对每个关系进行单独的查找,并进行加入";在 Python 中.

prefetch_related() does a separate lookup for each relationship, and does the "joining" in Python.

在 python 中加入"是什么意思?谁能举例说明一下?

What does it mean by "doing the joining in python"? Can someone illustrate with an example?

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

My understanding is that for foreign key relationship, use select_related; and for M2M relationship, use prefetch_related. Is this correct?

推荐答案

你的理解大多是正确的.当您要选择的对象是单个对象时,您可以使用 select_related,例如 OneToOneFieldForeignKey.当您要获得一组东西"时,您使用 prefetch_related,因此如您所说的 ManyToManyField 或反向 ForeignKey.只是为了澄清我所说的反向 ForeignKeys"的意思,这里有一个例子:

Your understanding is mostly correct. You use select_related when the object that you're going to be selecting is a single object, so OneToOneField or a ForeignKey. You use prefetch_related when you're going to get a "set" of things, so ManyToManyFields as you stated or reverse ForeignKeys. Just to clarify what I mean by "reverse ForeignKeys" here's an example:

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 的任何内容.

The difference is that select_related does an SQL join and therefore gets the results back as part of the table from the SQL server. prefetch_related on the other hand executes another query and therefore reduces the redundant columns in the original object (ModelA in the above example). You may use prefetch_related for anything that you can use select_related for.

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

The tradeoffs are that prefetch_related has to create and send a list of IDs to select back to the server, this can take a while. I'm not sure if there's a nice way of doing this in a transaction, but my understanding is that Django always just sends a list and says SELECT ... WHERE pk IN (...,...,...) basically. In this case if the prefetched data is sparse (let's say U.S. State objects linked to people's addresses) this can be very good, however if it's closer to one-to-one, this can waste a lot of communications. If in doubt, try both and see which performs better.

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

Everything discussed above is basically about the communications with the database. On the Python side however prefetch_related has the extra benefit that a single object is used to represent each object in the database. With select_related duplicate objects will be created in Python for each "parent" object. Since objects in Python have a decent bit of memory overhead this can also be a consideration.

这篇关于Django ORM 中的 select_related 和 prefetch_related 有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆