django中查询的select_related方法和prefetch_related方法

select_related - 数据库上的join

Django考虑到了标准查询这种低效的查询方式,因此在设计ORM的时候设计了提升性能的方式。select_related就是其中之一。select_related将会根据外键关系,在执行查询语句的时候一次性获得相关对象的信息,这种操作带来的结果是更加复杂的查询语句和避免对于即将使用的外键对象的额外数据库查询。Django的文档详细的描述了相关内容,在此只进行简要介绍。标准的查询代码如下:

b = B.objects.get(id=2)
a = b.a

换用select_related之后,代码如下:

b = B.objects.select_related('a').get(id=2)  

'a’是B模型存在关联的A模型,指定a可以只查询A和B的数据,如果没有参数,则查询出所有相关联的model信息。
我们可以看到,select_related实际上是在数据库层面进行了一次inner join操作,因此一次性获取了所有需要的信息,也就是说使用select_related()方法一次性的把B关联的对象都查询出来放入对象中,再次查询时就不需要再连接数据库,节省了后面查询数据库的次数和时间。

需要注意的是,我们可以使用任意外键关系(ForeignKeyField)或一对一关系(OneToOneField)作为参数传给select_related,同时也可以使用反向的一对一关系,此时应使用related_name作为参数。某些情况下,你可能想获取所有的相关对象,或者你并不知道关联关系,此时可以使用不加参数的.select_related(),该方式下将会根据关联关系(级联的)获取所有关联的对象, 即假设有外键关系为A。

prefetch_related - Python上的join

与select_related类似,prefetch_related也可以大幅提高查询效率,但是prefetch_related的方式跟select_related大不一样。select_reateld是通过创建一条包含SQL join操作的SELECT语句来一次性获得所有相关对象的信息。因此,select_related需要从同一个数据库中获得相关对象。但是,为了避免由于join操作带来的较大的查询集结果,select_related被限制在了单值关系——外键关系或一对一关系

另一方面,prefetch_related为每一个关系使用了单独的查询,并在Python层面进行’join’操作,因此该操作允许多对多关系以及反向关系,而这是select_related无法做到的。我们这次使用prefetch_related执行查询,代码如下:

b = B.objects.prefetch_related('a').get(id=2)

可以看到,Django首先进行了id=5的第一次查询获取对象b,然后根据外键关系进行了第二次查询获取b.a。为了增强理解,我们引入第三个模型C,这次我们从A模型上查询id__lte=5的A对象及其相关对象,代码如下:

class C(models.Model):
	b = models.Foreignkey(B, related_name='cs')
qs = A.objects.prefetch_related('bs', 'bs__cs').filter(id__lte=5)

Django首先查询了id小于等于5的所有A对象,然后根据反向关联关系,查询所有外键到这些A对象的B对象,然后查询所有外键到这些B对象的C对象。

select_related与prefetch_related性能对比:
在查询集中的对象字段较多较复杂,且查询集较大的时候,或需要使用反向外键关系或多对多关系作为参数优化查询的时候,应该选用prefetch_related,在查询集中对象字段简单的,查询集不大的时候,应选用select_related。

下面链接介绍的更详细:

https://blog.csdn.net/cugbabybear/article/details/38342793

你可能感兴趣的:(Django,python,mysql,select_related)