django ORM优化之select_related

本文转载自https://www.douban.com/note/533925129/

版权归作者所有,任何形式转载请联系作者。
作者:petanne(来自豆瓣)
来源:https://www.douban.com/note/533925129/

补充:django1.5版本之后已经将select_related的**kwargs即depth删除了,递归机制与之前相同,即fields不传参数的时候默认递归查询related的所有字段,但django在源码里写死了最大递归深度depth为5,此前为无限。源码变为select_related(*fields)。查询过程与之前版本相同。

==============================原内容===================================
源码说明:
Returns a new QuerySet instance that will select related objects.  # 默认的related objects为ForeignKey 和 OneToOneField 
If fields are specified, they must be ForeignKey fields and only those related objects are included in the selection.

select_related(*fields, **kwargs)
此处kwargs只接收depth一个参数,传其它值抛异常,且fields和depth同时只能使用一个,否则抛异常。

假设有一个员工表,结构如下
Class Employee(models.Model):
    dept = models.ForeignKey(Department, verbose_name=u'部门')
    level = models.ForeignKey(Level, verbose_name=u'薪资级别', blank=True, null=True)

>>employee = Employee.objects.get(id=1)
>>dept = employee.dept  # 又一次查询了数据库
>>level = employee.level  # 又一次查询了数据库

>>employee = Employee.objects.select_related('dept').get(id=1)
>>dept = employee.dept  # 没查询数据库
>>level = employee.level  # 又一次查询了数据库

>>employee = Employee.objects.select_related('dept__name').get(id=1)
>>name = employee.dept.name  # 没查询数据库

>>employee = Employee.objects.select_related('dept', 'level').get(id=1)
>>dept = employee.dept  # 没查询数据库
>>level = employee.level  # 没查询数据库

>>employee = Employee.objects.select_related(depth=1).get(id=1)
>>dept = employee.dept  # 没查询数据库,性能与上面写法相同
>>level = employee.level  # 没查询数据库,性能与上面写法相同

>>employee = Employee.objects.select_related().get(id=1)
>>dept = employee.dept  # 没查询数据库,性能小于等于上面写法
>>level = employee.level  # 没查询数据库,性能小于等于上面写法

注意!select_related不传任何参数的时候,默认会查询所有的关联对象,且会递归INNER JOIN所有的非空外键!!!如果Department表里有一个非空外键Region,那么会同时查询Region.id, Region.name, Region.other等!假如Region表又有一个非空外键Country,那么依然会全部INNER JOIN出来,性能消耗会呈指数型增长!若Department表的Region外键可空,那么只会查询到Region.id,不会进行递归。

对此,select_related提供了关键字参数depth,默认为0,即递归直到最后一个对象没有非空外键为止。depth为1时只递归一级外键,以此类推。

select_related的字段写法支持ORM语法,比如select_related('dept__name'),看起来像是只多select了Department的name属性,但是实际和select_related('dept')一样会将dept的所有属性查询出来,亲测目前django1.9版本是这个情况。

select_related('dept')与select_related(depth=1)效果完全一样,不论外键Region可空或非空,都只查询到Department.Region_id就截止了。所以使用select_related最好至少传一种参数!至少传一种参数!至少传一种参数!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值