Django查询优化之select_related和prefetch_related

简介:

一、select_related查询优化

    select_related通过多表join关联查询,一次性获得所有数据,通过降低数据库查询次数来提升性能,但关联表不能太多,因为join操作本来就比较消耗性能。本文通过Django debug toolbar工具来直观显示查询次数、查询语句,如果不会使用“Django debug toolbar”工具,可以翻看我之前写的博客,从而配置它!

1
2
3
model.tb.objects. all ().select_related()
model.tb.objects. all ().select_related( '外键字段' )
model.tb.objects. all ().select_related( '外键字段__外键字段' )

models.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from  django.db  import  models
 
class  Publisher(models.Model):
     name  =  models.CharField(max_length = 30 , verbose_name = "名称" )
     address  =  models.CharField( "地址" , max_length = 50 )
     city  =  models.CharField( '城市' , max_length = 60 )
     state_province  =  models.CharField(max_length = 30 )
     country  =  models.CharField(max_length = 50 )
     website  =  models.URLField()
 
     class  Meta:
         verbose_name  =  '出版商'
         verbose_name_plural  =  verbose_name
 
     def  __str__( self ):
         return  self .name
 
class  Author(models.Model):
     name  =  models.CharField(max_length = 30 )
     hobby  =  models.CharField(max_length = 20 , default = "", blank = True )
 
     def  __str__( self ):
         return  self .name
 
class  Book(models.Model):
     title  =  models.CharField(max_length = 100 , verbose_name = "书名" )
     authors  =  models.ManyToManyField(Author)
     publisher  =  models.ForeignKey(Publisher, verbose_name = "出版社" )
     publication_date  =  models.DateField(null = True )
     price  =  models.DecimalField(max_digits = 5 , decimal_places = 2 , default = 10 , verbose_name = "价格" )
 
     def  __str__( self ):
         return  self .title

views.py

1
2
3
def  index(request):
     obj  =  Book.objects. all ()
     return  render(request,  "index.html" locals ())

index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html lang = "en" >
<head>
     <meta charset = "UTF-8" >
     <title>Title< / title>
< / head>
<body>
     <p>django debug toolbar!< / p>
     { %  for  item  in  obj  % }
         <div>{{ item.title }} {{ item.price }} {{ item.publisher.name }}< / div>
     { %  endfor  % }
< / body>
< / html>


    当我们没有使用select_related时,在前端模板中,每一次循环就要向数据库发送一次请求,因为我表中数据很少,所有只发起了7次查询,但实际生产中每个表的数据肯定是成千上万的,传统的操作对数据库的性能影响很大!

09869b38c62104efa810056359cf02bd.png


当我们使用select_related连表操作时,请看下例,只发起了两次查询!!!

1
2
3
def  index(request):
     obj  =  Book.objects. all ().select_related( "publisher" )
     return  render(request,  "index.html" locals ())


2bad9015ec1e9623715345e2a7fa6fd0.png-wh_

总结:

  1. select_related主要针一对一和多对一关系进行优化。

  2. select_related使用SQL的JOIN语句进行优化,通过减少SQL查询的次数来进行优化、提高性能。

  3. 可以通过可变长参数指定需要select_related的字段名。也可以通过使用双下划线“__”连接字段名来实现指定的递归查询(也就是外键的外键,多层连表查询)。没有指定的字段不会缓存,没有指定的深度不会缓存,如果要访问的话Django会再次进行SQL查询。


二、prefetch_related查询优化

    prefetch_related()和select_related()的设计目的很相似,都是为了减少SQL查询的数量,但是实现的方式不一样。后者是通过JOIN语句,在SQL查询内解决问题。但是对于多对多关系,使用SQL语句解决就显得有些不太明智,因为JOIN得到的表将会很长,会导致SQL语句运行时间的增加和内存占用的增加。prefetch_related()的解决方法是,分别查询每个表,然后用Python处理他们之间的关系!

1
models.tb.objects.prefetch_related( '外键字段' )


我们还是通过上例来举例:

1
2
3
def  index(request):
     obj  =  Book.objects. all ().prefetch_related( "publisher" )
     return  render(request,  "index.html" locals ())



74f361d703e0c38264459d1da47b4c34.png4b515eeaf266edf23749f99a9da796e5.png

    使用prefetch_related优化查询,貌似发起了四次数据库请求,但实际是只有两次的,就是图中划横线的SQL语句,其他两条是session相关的,我们不用理会。我来解释一下prefetch_related是怎么发起请求的,第一步:先拿到book表的所有数据;第二步:通过select .. from ... where ... in (book表中所有出版社的外键ID)。这样通过分别发起两次请求,获取了book表以及和book表相关联的publisher表的数据(并不是所有publisher表数据,只有和book表相关联数据!),然后通过Python处理数据的对应关联。

总结:

  1. prefetch_related主要针一对多和多对多关系进行优化。

  2. prefetch_related通过分别获取各个表的内容,然后用Python处理他们之间的关系来进行优化。


大结局:

    select_related是通过join来关联多表,一次获取数据,存放在内存中,但如果关联的表太多,会严重影响数据库性能。

    prefetch_related是通过分表,先获取各个表的数据,存放在内存中,然后通过Python处理他们之间的关联。

本文转自戴柏阳的博客博客51CTO博客,原文链接http://blog.51cto.com/daibaiyang119/1977637如需转载请自行联系原作者

daibaiyang119
相关文章
|
SQL Python
这个贴子的内容值得好好学习--实例详解Django的 select_related 和 prefetch_related 函数对 QuerySet 查询的优化
感觉要DJANGO用得好,ORM必须要学好,不管理是内置的,还是第三方的ORM。 最最后还是要到SQL。。。。。:( 这一关,慢慢练啦。。   实例详解Django的 select_related 和 prefetch_related 函数对 QuerySet 查询的优化 http://blog.
1195 0
|
4月前
|
搜索推荐 前端开发 数据可视化
【优秀python web毕设案例】基于协同过滤算法的酒店推荐系统,django框架+bootstrap前端+echarts可视化,有后台有爬虫
本文介绍了一个基于Django框架、协同过滤算法、ECharts数据可视化以及Bootstrap前端技术的酒店推荐系统,该系统通过用户行为分析和推荐算法优化,提供个性化的酒店推荐和直观的数据展示,以提升用户体验。
172 1
【优秀python web毕设案例】基于协同过滤算法的酒店推荐系统,django框架+bootstrap前端+echarts可视化,有后台有爬虫
|
4月前
|
机器学习/深度学习 数据采集 数据可视化
基于爬虫和机器学习的招聘数据分析与可视化系统,python django框架,前端bootstrap,机器学习有八种带有可视化大屏和后台
本文介绍了一个基于Python Django框架和Bootstrap前端技术,集成了机器学习算法和数据可视化的招聘数据分析与可视化系统,该系统通过爬虫技术获取职位信息,并使用多种机器学习模型进行薪资预测、职位匹配和趋势分析,提供了一个直观的可视化大屏和后台管理系统,以优化招聘策略并提升决策质量。
215 4
|
1月前
|
设计模式 前端开发 数据库
Python Web开发:Django框架下的全栈开发实战
【10月更文挑战第27天】本文介绍了Django框架在Python Web开发中的应用,涵盖了Django与Flask等框架的比较、项目结构、模型、视图、模板和URL配置等内容,并展示了实际代码示例,帮助读者快速掌握Django全栈开发的核心技术。
169 45
|
1月前
|
安全 数据库 开发者
Python Web开发:Django框架下的全栈开发实战
【10月更文挑战第26天】本文详细介绍了如何在Django框架下进行全栈开发,包括环境安装与配置、创建项目和应用、定义模型类、运行数据库迁移、创建视图和URL映射、编写模板以及启动开发服务器等步骤,并通过示例代码展示了具体实现过程。
59 2
|
1月前
|
安全 数据库 C++
Python Web框架比较:Django vs Flask vs Pyramid
Python Web框架比较:Django vs Flask vs Pyramid
43 1
|
3月前
|
机器学习/深度学习 人工智能 算法
植物病害识别系统Python+卷积神经网络算法+图像识别+人工智能项目+深度学习项目+计算机课设项目+Django网页界面
植物病害识别系统。本系统使用Python作为主要编程语言,通过收集水稻常见的四种叶片病害图片('细菌性叶枯病', '稻瘟病', '褐斑病', '稻瘟条纹病毒病')作为后面模型训练用到的数据集。然后使用TensorFlow搭建卷积神经网络算法模型,并进行多轮迭代训练,最后得到一个识别精度较高的算法模型,然后将其保存为h5格式的本地模型文件。再使用Django搭建Web网页平台操作界面,实现用户上传一张测试图片识别其名称。
142 22
植物病害识别系统Python+卷积神经网络算法+图像识别+人工智能项目+深度学习项目+计算机课设项目+Django网页界面
|
2月前
|
安全 数据库 C++
Python Web框架比较:Django vs Flask vs Pyramid
Python Web框架比较:Django vs Flask vs Pyramid
41 4
|
3月前
|
机器学习/深度学习 算法 TensorFlow
交通标志识别系统Python+卷积神经网络算法+深度学习人工智能+TensorFlow模型训练+计算机课设项目+Django网页界面
交通标志识别系统。本系统使用Python作为主要编程语言,在交通标志图像识别功能实现中,基于TensorFlow搭建卷积神经网络算法模型,通过对收集到的58种常见的交通标志图像作为数据集,进行迭代训练最后得到一个识别精度较高的模型文件,然后保存为本地的h5格式文件。再使用Django开发Web网页端操作界面,实现用户上传一张交通标志图片,识别其名称。
123 6
交通标志识别系统Python+卷积神经网络算法+深度学习人工智能+TensorFlow模型训练+计算机课设项目+Django网页界面
|
3月前
|
机器学习/深度学习 人工智能 算法
【新闻文本分类识别系统】Python+卷积神经网络算法+人工智能+深度学习+计算机毕设项目+Django网页界面平台
文本分类识别系统。本系统使用Python作为主要开发语言,首先收集了10种中文文本数据集("体育类", "财经类", "房产类", "家居类", "教育类", "科技类", "时尚类", "时政类", "游戏类", "娱乐类"),然后基于TensorFlow搭建CNN卷积神经网络算法模型。通过对数据集进行多轮迭代训练,最后得到一个识别精度较高的模型,并保存为本地的h5格式。然后使用Django开发Web网页端操作界面,实现用户上传一段文本识别其所属的类别。
107 1
【新闻文本分类识别系统】Python+卷积神经网络算法+人工智能+深度学习+计算机毕设项目+Django网页界面平台