prefetch_related和select_related的区别

prefetch_related和select_related的区别,以及更深入的应用

这两个方法实在是太常见了,尤其是select_related已经在业务代码中使用过很多次,但是这次需要来对这两个在很多方面相似的函数在使用层面上做一个彻底的分析来明确它们的区别


如果非要从返回的结果这个视角来看这两者的作用,那么其实一句话就可以概括了:select_related的功能是prefetch_related的子集,任何可以用select_related实现的逻辑,prefetch_related都可以同样实现

然而如果真的现实中的情况如上面这句话一般,那django设计select_related这个方法就完全是多余的了,这明显是不可能的,所以下面来具体讲一下它们的区别

假设我们的项目中有如下模型

class Messages(CommonInfo):record_type = models.ForeignKey('ObjectRecordTypes', models.DO_NOTHING)product = models.ForeignKey(Products, blank=True, null=True)content = models.TextField(max_length=500, blank=True, null=True)description = models.TextField(max_length=500, blank=True, null=True)display_order = models.IntegerField(3)owner = models.ForeignKey(User, models.DO_NOTHING, db_column='owner',blank=True, null=True)external_id = models.CharField(max_length=255, default=None, blank=True,null=True)class Meta:db_table = 'messages'

上面这个message模型有一个product外键关联向Products类,而根据django orm的foreign key定义,这个外键指的就是可以有多条message对象同时指向一条product对象,也就是典型的多对一,另外因为这里的product字段在定义时属性中并没有对related_name这个属性进行设置,所以这里是可以通过product对象反向找到外键关联它的所有message的

好了,准备工作完成,再看下具体使用select_related和prefetch_related是什么情况吧

>>> models.Products.advance_objects.select_related('messages_set').filter(id__lt=100)
print result
>>> FieldError: Invalid field name(s) given in select_related: 'messages_set'.
>>> models.Products.advance_objects.prefetch_related('messages_set').filter(id__lt=100)
>>> print result
>>> (正常显示结果)

上面这个例子在某种程度上更加清晰的解释了django文档中对这两个方法的不同的描述:select_related是在关联的对象确定只有一个的情况下才能使用,prefetch_related则不管关联的对象有几个,全部可以使用,因为它取的是一个集合

不同的地方说完了,再来说下产生结果相同的一种情况

>>> result = models.EventExpenses.advance_objects.select_related('event').get(pk=1)
>>> 取到一个会议费用的对象,同时将费用外键关联的会议对象的信息也取到了
>>> result = models.EventExpenses.advance_objects.prefetch_related('event').get(pk=1)
>>> 取到一个会议费用的对象,同时将费用外键关联的会议对象的信息也取到了

从上面看起来,两个操作拿到的结果是一样的,那区别在哪里呢,我们仔细看一下orm打印的日志,区别就很明显了,首先对于select_related,后台只执行了一条SQL语句

SELECT `event_expenses`.xxx,  `events`.xxx
FROM `event_expenses`
INNER JOIN `events`
ON (`event_expenses`.`event_id` = `events`.`id`)
WHERE xxx=xxx;

显而易见,这里select_related采用了join内连接方式将两张表关联起来,所以只用了一条SQL语句

再看prefetch_related

SELECT `event_expenses`.xxx FROM `event_expenses` WHERE xxx=xxx;
SELECT `events`.xxx FROM `events` WHERE `events`.`id` IN (xxx, xxx);

这里prefetch执行了两条语句来拿到外键关联的数据,同时第二条数据采用的SQL语句是用了IN谓语的sql,这样再看就能发现,虽然它们取到的结果是一样的,但是prefetch_related操作明显更费时,不仅是因为它执行了两条SQL语句,还因为第二条SQL语句使用了SQL中很费时的IN谓语来进行判断

结论

通过上面的例子再看,实际上也可以很明显的知道这两个方法各自的应用场景了:在关联的外键可能指向多个数据对象时,prefetch_related是唯一选择,而在外键指向的是一个唯一对象时,select_related方法明显要比prefetch_related高效,虽然prefetch_related也能用

实际场景1

今天在项目代码review的过程中老司机提了一句select_related的用法问题,假设有一个Blog,有几篇Article关联到这个blog对象,如果我们通过其中一篇article实例找关联的blog的名字,我们很可能下意识的写出下面的语句

Article.objects.select_related('blog__name').filter(xxx=xxx)

但是上面的情况经过试验,实际上是有问题的,这样去用select_related实际上还是会取到blog所有字段的值,同时在某些情况下这种blog__name的queryset还会报错,因为name字段根本不是外键,所以这里明确了一个事情即:select_related方法里的字段都应该是外键关联字段,而不是普通字段

prefetch_related和select_related的区别相关推荐

  1. union和union all有什么区别_Django基础(29):select_related和prefetch_related的用法与区别...

    在前面教程中小编我已经介绍了Django的Queryset特性及高级使用技巧以及Queryset的aggregate和annotate方法.这些技巧和方法都是为了减少对数据库的访问次数和对内存的占用, ...

  2. Django的 select_related 和 prefetch_related 函数对 QuerySet 查询的优化(二)

    3. prefetch_related() 对于多对多字段(ManyToManyField)和一对多字段,可以使用prefetch_related()来进行优化.或许你会说,没有一个叫OneToMan ...

  3. 实例具体解释Django的 select_related 和 prefetch_related 函数对 QuerySet 查询的优化(二)...

    这是本系列的第二篇,内容是 prefetch_related() 函数的用途.实现途径.以及用法. 本系列的第一篇在这里 第三篇在这里 3. prefetch_related() 对于多对多字段(Ma ...

  4. select_related与prefetch_related django ORM查询速度优化

    深入select_related与prefetch_related函数 原文:https://www.cnblogs.com/tuifeideyouran/p/4232028.html 在数据库有外键 ...

  5. Django中的prefetch_related()函数优化

    对于多对多字段(ManyToManyField)和一对多字段, 可以使用prefetch_related()来进行优化 prefetch_related()和select_related()的设计目的 ...

  6. Django中QuerySet查询优化之prefetch_related详解

    在数据库有外键的时候,使用 select_related() 和 prefetch_related() 可以很好的减少数据库请求的次数,从而提高性能.本文通过一个简单的例子详解这两个函数的作用.虽然Q ...

  7. Django中prefetch_related()函数优化实战指南

    对于多对多字段(ManyToManyField)和一对多字段, 可以使用prefetch_related()来进行优化 prefetch_related()和select_related()的设计目的 ...

  8. Python自动化运维:Django Model进阶

    QuerySet 可切片 使用Python 的切片语法来限制查询集记录的数目 .它等同于SQL 的LIMIT 和OFFSET 子句. >>> Entry.objects.all()[ ...

  9. Web框架之Django_06 模型层了解(F查询、Q查询、事务、update和save、only和defer、choice属性、bulk_create)

    阅读目录 一.F查询 二. Q查询 三.事务 四.补充的一些常用的操作 摘要: F查询 Q查询 事务 一.F查询 在上面所有的例子中,我们构造的过滤器都只是将字段值与某个我们自己设定的常量做比较.如果 ...

  10. Django-model进阶

    知识预览 QuerySet 中介模型 查询优化 extra 整体插入 回到顶部 QuerySet 可切片 使用Python 的切片语法来限制查询集记录的数目 .它等同于SQL 的LIMIT 和OFFS ...

最新文章

  1. 基于hsv的亮度调整算法_改变HSV的H和V部分(比如可以增加图像亮度)
  2. 在Dialog中实现下拉框效果并对下拉框赋自定义的值
  3. 学业水平测试计算机模拟,高二计算机学业水平测试 模拟试题(附答案)
  4. linux网站爬取,Kali下httrack 爬取网站页面
  5. oracle删除当前用户下所有表
  6. Android的xml/assets/raw资源使用具体解释
  7. coc部落冲突关联错误101解决方案
  8. xilinx官方教程ug871利用HLS实现RealFFT
  9. 罗盘时钟制作代码_抖音超火的姓氏罗盘壁纸,安卓和苹果都能做
  10. DNF自动获取C语言,VC++开发硬件DNF搬砖项目全新发车,想上车的要赶紧
  11. CKEditor5富文本编辑器在vue中的使用
  12. android高德地图关键字搜索,关键字搜索-POI搜索-示例中心-JS API 示例 | 高德地图API...
  13. 以非本地Administrator身份登录的客户机无法访问服务器共享文件夹,显示句柄无效。
  14. Android源码目录结构详解(转载)
  15. C语言聊天室项目说明书
  16. ROS教程(二):创建工作空间(图文)
  17. 小巧高效的php框架,猿团YTFramework框架上线 让PHP开发更简单高效
  18. geoserver 官方文档翻译(其一)----- CQL and ECQL cql_filter例子
  19. (一)ssh远程连接服务器GPU以及其他GPU使用途径——新手指南
  20. Spark的性能优化案例分析(下)

热门文章

  1. C 语言基础-什么是常量、变量?
  2. RPC框架的使用场景
  3. java三三剩二五五剩三,大年三十彩灯悬,彩灯齐明光灿灿,三三数时能数尽,五五数时剩一盏,七七数时刚刚好,八八数时还缺三,...
  4. Python学习笔记之os模块
  5. java制作oa审批流程,传智播客JAVA培训OA项目 审批流转模块
  6. 腾讯微博qq说说备份导出工具_软件推荐Day51 其他工具类 腾讯微博备份
  7. “New”一个完美对象,再来好好面向对象
  8. windows下解决弹窗广告
  9. Workface通用核算项目的实现
  10. HDU4565 So Easy!【矩阵快速幂】