Django ORM select_related 和 prefetch_related

Foreign key in the database when using select_related () and prefetch_related () may well reduce the number of database requests, thereby improving performance.

In the example described, both the usage:

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:
For one-field (OneToOneField) and foreign key fields (ForeignKey), may be used to optimize the select_related QuerySet. Select_related QuerySet that after use of () function, Django will obtain the corresponding foreign key corresponding to the object, so that when no longer needed after the database query.

If we need to print all cities and provinces and their respective databases, the most direct approach is:

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

This will result in a linear SQL query, if the number of objects n too much, each object has a foreign key field k, it would lead to n * k + 1 times SQL queries. In this case, because there are three objects has led to the city four times SQL query:

SELECT `QSOptimize_city`.`id`, `QSOptimize_city`.`name`, `QSOptimize_city`.`province_id`
FROM `QSOptimize_city`
 
SELECT `QSOptimize_province`.`id`, `QSOptimize_province`.`name` 
FROM `QSOptimize_province`
WHERE `QSOptimize_province`.`id` = 1 ;
 
SELECT `QSOptimize_province`.`id`, `QSOptimize_province`.`name` 
FROM `QSOptimize_province`
WHERE `QSOptimize_province`.`id` = 2 ;
 
SELECT `QSOptimize_province`.`id`, `QSOptimize_province`.`name` 
FROM `QSOptimize_province`

If we use select_related () function:

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

Only one SQL query, apparently greatly reduce the number of SQL queries:

SELECT `QSOptimize_city`.`id`, `QSOptimize_city`.`name`, 
`QSOptimize_city`.`province_id`, `QSOptimize_province`.`id`, `QSOptimize_province`.`name` 
FROM`QSOptimize_city` 
INNER JOIN `QSOptimize_province` ON (`QSOptimize_city`.`province_id` = `QSOptimize_province`.`id`) ;

prefetch_related ()
for a many to many fields (ManyToManyField) and many fields, may be used prefetch_related () to optimize. Perhaps you will say, no one called OneToManyField thing ah. In fact, ForeignKey is a many-to-field, but the field is ForeignKey is associated with many of the field.
prefetch_related () and select_related () is designed very similar, is to reduce the number of SQL queries, but not the same way to achieve. (The former is the statement by IN) JOIN statement by the latter , to solve the problem in a SQL query. But for many relationships, use the SQL statement to address on a bit unwise, because JOIN resulting table will be very long, it will lead to increased memory footprint and increase the running time of SQL statements. If n objects, each object corresponding to a field-many Mi article, [Sigma result table is generated (n) Mi row.

prefetch_related () The workaround is to query each table separately, and then deal with their relationship with Python . We want to get all the City of Hubei Province, it can be

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

Triggered SQL query:

SELECT `QSOptimize_province`.`id`, `QSOptimize_province`.`name` 
FROM `QSOptimize_province` 
WHERE `QSOptimize_province`.`name` LIKE '湖北省' ;

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

We can see, prefetch using the IN statement to achieve.

Summary:
Since select_related () always resolved in a single SQL query in question, but prefetch_related () will each relevant table SQL query , so select_related () the efficiency is usually higher than the latter.

Published 44 original articles · won praise 0 · Views 3921

Guess you like

Origin blog.csdn.net/cpxsxn/article/details/104759607