程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

Django ORM related operations select_ Related and prefetch_ Optimization of queryset query by related function

編輯:Python

If there are foreign keys in the database , Use select_related() and prefetch_related() Greatly reduce the number of requests to the database to improve performance

The main idea is ‘ When we look up a data item in the table , We Handy Connect the relational data items in other tables connected to this data item , Find it together , So when we operate on this data item , You can directly operate just Handy The relational data items , Instead of going to the database again ’

1, The scope of application of both

select_related() For one-on-one OneToOneField and For one more ( It's the foreign key )ForeignKey
prefetch_related() Apply to Many to many ManyToManyField and One to many ( I call it The reverse foreign key , It's the one in the foreign key table related_name The value of the inside )

class Pic(models.Model):
xx = models.CharField(max_length=30)
album = models.ForeignKey(to=Album, on_delete=models.CASCADE, related_name='pic')
// Like the one below prefetch_related('tags', 'pic') Medium ‘pic'
album = Album.objects.prefetch_related('tags', 'pic').get(pk=id)
// But if from Pic In terms of , Connect album Words , Just use select_related()
pic = Pic.objects.select_related('album').get(pk=id)


The following is a copy :
https://www.cnblogs.com/mdzzbojo/p/9216122.html

Django Of select_related and prefetch_related Function pair QuerySet Query optimization
introduction

If there are foreign keys in the database , Use select_related() and prefetch_related() Greatly reduce the number of requests to the database to improve performance

1. Example preparation

Model :
Copy code

from django.db import models

Create your models here.

book

class Book(models.Model):
title = models.CharField(max_length=32)
publish_date = models.DateField(auto_now_add=True)
price = models.DecimalField(max_digits=5, decimal_places=2)
memo = models.TextField(null=True)
# Create foreign keys , relation publish
publisher = models.ForeignKey(to=“Publisher”, on_delete=models.CASCADE, related_name=‘books’)
# Create many to many associations author
author = models.ManyToManyField(to=“Author”)

def __str__(self):
return self.title

Press.

class Publisher(models.Model):
name = models.CharField(max_length=32)
city = models.CharField(max_length=32)

def __str__(self):
return self.name

author

class Author(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
phone = models.CharField(max_length=11)
detail = models.OneToOneField(to=“AuthorDetail”, on_delete=models.CASCADE)

def __str__(self):
return self.name

The author details

class AuthorDetail(models.Model):
addr = models.CharField(max_length=64)
email = models.EmailField()

Copy code

1.select_related()

For one-to-one fields (OneToOneField) And foreign key fields (ForeignKey) have access to select_releated To optimize QuerySet Inquire about

Example :

1) When the method is not called , Check all books and publishing houses

book_obj = models.Book.objects.all()

Print all books and publishing houses

for book in book_obj:
print(book.publisher)

Output log information
Copy code

(0.000) SELECT @@SQL_AUTO_IS_NULL; args=None
(0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None
(0.001) SELECT app_book.id, app_book.title, app_book.publish_date, app_book.price, app_book.memo, app_book.publisher_id FROM app_book; args=()
Southern media press
Changsha TV press
Changsha TV press
tsinghua university press
People's post and Telecommunications Press
(0.001) SELECT VERSION(); args=None
Southern media press
(0.001) SELECT app_publisher.id, app_publisher.name, app_publisher.city FROM app_publisher WHERE app_publisher.id = 1; args=(1,)
(0.001) SELECT app_publisher.id, app_publisher.name, app_publisher.city FROM app_publisher WHERE app_publisher.id = 2; args=(2,)
(0.000) SELECT app_publisher.id, app_publisher.name, app_publisher.city FROM app_publisher WHERE app_publisher.id = 2; args=(2,)
(0.000) SELECT app_publisher.id, app_publisher.name, app_publisher.city FROM app_publisher WHERE app_publisher.id = 4; args=(4,)
(0.001) SELECT app_publisher.id, app_publisher.name, app_publisher.city FROM app_publisher WHERE app_publisher.id = 3; args=(3,)
(0.000) SELECT app_publisher.id, app_publisher.name, app_publisher.city FROM app_publisher WHERE app_publisher.id = 1; args=(1,)

Process finished with exit code 0

Copy code

2) When the method is called , Check all books and publishing houses

book_obj = models.Book.objects.select_related().all()
for book in book_obj:
print(book.publisher)

Output log information
Copy code

(0.001) SELECT @@SQL_AUTO_IS_NULL; args=None
(0.001) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None
(0.001) SELECT app_book.id, app_book.title, app_book.publish_date,
app_book.price, app_book.memo, app_book.publisher_id, app_publisher.id,
app_publisher.name, app_publisher.city FROM app_book INNER JOIN app_publisher
ON (app_book.publisher_id = app_publisher.id); args=()
Southern media press
Changsha TV press
Changsha TV press
tsinghua university press
People's post and Telecommunications Press
Southern media press

Process finished with exit code 0

Copy code

Conclusion :

In the face of QuerySet Use select_related() Function before , There will be linear SQL Inquire about , If there is n A query object , Every object exists k Foreign key fields , Will appear n*k + 1 Time SQL Inquire about

In the face of QuerySet Use select_related() After the function ,Django The object corresponding to the corresponding foreign key will be obtained during the first query , So you don't have to query the database when you need it later , Only one query is needed

3) Related parameters

*fields Parameters ,select_related() Accept variable length parameters , Each parameter is a foreign key to get ( The contents of the parent table ) Field name , And the field name of the foreign key 、 Foreign keys, foreign keys, foreign keys, etc , To select a foreign key for a foreign key, you need to use two underscores “__” To connect

Example : Get the detailed address of the publishing house of the book through the foreign key

obj = models.Book.objects.select_related(‘publisher__detail’).get(title=‘ Wulin legend ’)
print(obj.publisher.detail)
print(obj.publisher)

Output log information
Copy code

(0.000) SELECT @@SQL_AUTO_IS_NULL; args=None
(0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None
(0.000) SELECT VERSION(); args=None
(0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None
(0.001) SELECT app_book.id, app_book.title, app_book.publish_date, app_book.price, app_book.memo, app_book.publisher_id, app_publisher.id, app_publisher.name, app_publisher.city, app_publisher.detail_id, app_publisherdetail.id, app_publisherdetail.addr, app_publisherdetail.create_date FROM app_book INNER JOIN app_publisher ON (app_book.publisher_id = app_publisher.id) INNER JOIN app_publisherdetail ON (app_publisher.detail_id = app_publisherdetail.id) WHERE app_book.title = ‘ Wulin legend ’; args=(‘ Wulin legend ’,)
Changsha South District
Changsha TV press
Copy code

Conclusion :

Django Used 2 Time INNER JOIN To complete the request , To obtain the publisher Table and publisherdetail Table and add to the corresponding columns of the result table , There is no need to call these two objects again SQL Inquire about ; On the contrary, if it is an unspecified foreign key, it will SQL Inquire about , And deeper , More queries

depth Parameters ,select_related() Accept depth Parameters ,depth The parameters can be determined select_related The depth of the ,Django Recursively traverses all of the OneToOneField and ForeignKey

No parameter ,select_related() You can also add no parameters , It's a request Django As deep as possible select_related

summary :
Copy code

1.select_related It mainly focuses on one-to-one and many to one relationship optimization
2.select_related Use SQL Of JOIN Statement optimization , By reducing SQL Number of queries to optimize 、 Improve performance
3. You can specify the need through variable length parameters select_related Field name . You can also use double underscores “__” Connect field names to implement specified recursive queries . Fields not specified will not be cached , Will not cache without specified depth , If you want to visit Django It will be done again SQL Inquire about
4. It can also be done through depth Parameter to specify the depth of the recursion ,Django Will automatically cache all fields within the specified depth . If you want to access fields beyond the specified depth ,Django It will be done again SQL Inquire about
5. Also accept calls without parameters ,Django Will recursively query all fields as deep as possible . But notice that Django The limitation of recursion and the waste of performance
6.Django >= 1.7, Chain called select_related Equivalent to using variable length parameters .Django < 1.7, Chained calls lead to select_related invalid , Keep only the last one

Copy code

2.prefetch_releated()

For many to many fields (ManyToManyField) And one to many (ForeignKey) Field , You can use prefetch_related() To optimize , It and select_releated The design purpose of is similar , It's all about reducing SQL Number of queries , But the implementation is different , The latter is through JOIN Statements in SQL Solve the problem within the query . But because of JOIN The statement is too long , Not suitable for solving many to many relationships , It can lead to SQL The increase of statement running time and memory consumption

prefetch_releated The solution is to query each table separately , And then use Python Deal with their relationship

Example :

book_obj = models.Book.objects.prefetch_related(‘publisher’).get(title=‘ Seven Heroes and Five Gallants ’)
print(book_obj.publisher.detail)

Output log information
Copy code

(0.000) SELECT @@SQL_AUTO_IS_NULL; args=None
(0.001) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None
(0.000) SELECT VERSION(); args=None
(0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None
(0.000) SELECT app_book.id, app_book.title, app_book.publish_date, app_book.price, app_book.memo, app_book.publisher_id FROM app_book WHERE app_book.title = ‘ Seven Heroes and Five Gallants ’; args=(‘ Seven Heroes and Five Gallants ’,)
(0.000) SELECT app_publisher.id, app_publisher.name, app_publisher.city, app_publisher.detail_id FROM app_publisher WHERE app_publisher.id IN (1); args=(1,)
(0.001) SELECT app_publisherdetail.id, app_publisherdetail.addr, app_publisherdetail.create_date FROM app_publisherdetail WHERE app_publisherdetail.id = 1; args=(1,)
Tianhe District, Guangzhou

Process finished with exit code 0

Copy code

Conclusion :

It can be seen that , The first query statement gets the object to be operated , The key is that the second item gets the condition of the query result, that is ID, The third line is obtained through the second line ID Query results

We can see from the second query statement , Can see ,prefetch It uses IN Statement implementation . such , stay QuerySet When there are too many objects in , Depending on the characteristics of the database, it may cause performance problems

*lookups Parameters ,prefetch_related() stay Django < 1.7 There is only one usage . and select_related() equally ,prefetch_related() Deep query is also supported

It should be noted that , In the use of QuerySet When , Once the database request is changed in the chain operation , I used to use prefetch_related The cached data will be ignored . This can lead to Django Re request the database to get the corresponding data , This causes performance problems . The database change requests mentioned here refer to all kinds of filter()、exclude() And so on, will eventually change SQL The operation of the code . and all() It doesn't change the final database request , Therefore, it will not result in a re request to the database

summary :
Copy code

1.prefetch_related It mainly optimizes one to many and many to many relationships
2.prefetch_related Get the contents of each table separately , And then use Python Deal with the relationship between them to optimize
3. You can specify the need through variable length parameters select_related Field name . Specify the way and characteristics associated with select_related It's the same
4. stay Django >= 1.7 Can pass Prefetch Object to implement complex queries , But the lower version Django It seems that it can only be realized by itself
5. As prefetch_related Parameters of ,Prefetch Objects and strings can be mixed
6.prefetch_related The chained call of will put the corresponding prefetch Add in , Not replacement , There seems to be no difference based on different versions
7. You can pass in None To clear the previous prefetch_related

Copy code

inductive :

1. because select_related() It's always in a single shot SQL Solve the problem in the query , and prefetch_related() Each related table will be SQL Inquire about , therefore select_related() Is usually more efficient than the latter
2. In view of the first , Use... As much as possible select_related() solve the problem . Only in select_related() Think about it when you can't solve the problem prefetch_related()
3. Can be in a QuerySet Use... At the same time select_related() and prefetch_related(), Thereby reducing SQL Number of queries
4. Only prefetch_related() Previous select_related() It works , The rest will be ignored


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved