📌  相关文章
📜  django 中的 Prefetch_related 和 select_related 函数

📅  最后修改于: 2022-05-13 01:55:15.278000             🧑  作者: Mango

django 中的 Prefetch_related 和 select_related 函数

在 Django 中,select_related 和 prefetch_related 旨在阻止因访问相关对象而导致的数据库查询泛滥。在本文中,我们将看到它如何减少查询次数并使程序更快。

  • select_related() “遵循”外键关系,在执行查询时选择其他相关对象数据。
  • prefetch_related()对每个关系进行单独的查找,并在Python中进行“连接”。

当您要选择的对象是单个对象时,可以使用 select_related,因此 OneToOneField 或 ForeignKey。当您要获得一组“东西”时,您可以使用 prefetch_related ,因此您所说的 ManyToManyFields 或反转 ForeignKeys。只是为了澄清我所说的“反向外键”的意思。

举例说明 Prefetch_related 和 select_related 的概念——

上面的分类可能不太清楚让我们看一个例子:

class A(models.Model):
   pass
  
class B(models.Model):
   a = ForeignKey(ModelA)
  
  
# Forward ForeignKey relationship
A.objects.select_related('a').all()
  
# Reverse ForeignKey relationship
A.objects.prefetch_related('modelb_set').all() 

select_related通过多表join关联查询一次性获取所有数据,通过减少数据库查询次数来提高性能。它使用SQL的JOIN语句,通过减少SQL查询次数来优化和提高性能。后者是通过JOIN语句解决SQL查询中的问题。但是对于多对多的关系,用SQL语句来解决是不明智的,因为JOIN得到的表会很长,会导致SQL语句的运行时间和内存占用增加。 prefetch_related() 的解决办法是分别查询每个表,然后用Python处理它们的关系!

这里有些例子 :

Models.py reads as follows:

from django.db import models
  
class Province(models.Model):
   name = models.CharField(max_length = 10)
   def __unicode__(self):
       return self.name
  
class City(models.Model):
   name = models.CharField(max_length = 5)
   province = models.ForeignKey(Province)
   def __unicode__(self):
       return self.name
  
class Person(models.Model):
   firstname = models.CharField(max_length = 10)
   lastname = models.CharField(max_length = 10)
   visitation = models.ManyToManyField(City, related_name = "visitor")
   hometown = models.ForeignKey(City, related_name = "birth")
   living = models.ForeignKey(City, related_name = "citizen")
   def __unicode__(self):
       return self.firstname + self.lastname

select_related –

我们使用 select_related()函数:

>>> citys = City.objects.select_related().all()
>>> for c in citys:
...   print c.province
...

只有一个 SQL 查询,这显然大大减少了 SQL 查询的数量:

SELECT `Optimize_city`.`id`, `Optimize_city`.`name`,
`Optimize_city`.`province_id`, `Optimize_province`.`id`, `Optimize_province`.`name`
FROM`Optimize_city`
INNER JOIN `Optimize_province` ON
(`Optimize_city`.`province_id`=`Optimize_province`.`id`);

prefetch_related –

在这里我们可以看到 Django 使用了 INNER JOIN。我想澄清一件事,Optimize 是我们应用程序的名称。如果我们想获取湖北的所有城市名称,我们可以这样做:

> HB=Province.objects.prefetch_related('city_set').get(name__iexact=u"Hubei Province")
>>> for city in hb.city_set.all():
...   city.name
...

触发的 SQL 查询:

SELECT `Optimize_province`.`id`, `Optimize_province`.`name`
FROM `Optimize_province`
WHERE `Optimize_province', `name `LIKE'Hubei Province';

SELECT `Optimize_city`.`id`, `Optimize_city`.`name`, `Optimize_city`.`province_id`
FROM `Optimize_city`
WHERE `Optimize_city`.`province_id` IN (1);

如我们所见,预取是使用 IN 语句实现的。这样,当QuerySet中的对象过多时,可能会出现性能问题,具体取决于数据库的特性。