Django是一个基于Python的网站开发框架,一个很重要的特色就是Battery Included,简单来讲就是包含了常规开发中所须要的一切东西,包括但不限于完整的ORM模型、中间件、会话处理、模板语言、路由映射、管理员站点等,大大提升了开发者的开发体验,今天要谈的东西即是属于Django ORM这块中查询集优化的内容。数据库
在实际的开发中,模型之间常常存在复杂的关联关系。在数据量较大的状况下,默认的查询可能面临潜在的性能问题。今天咱们就分享一下Django ORM的查询优化。框架
首先须要明确一点:post
Queryset是惰性求值的。性能
在Django中,全部的Queryset都是惰性的,意思是当建立一个查询集的时候,并无跟数据库发生任何交互。所以咱们能够对查询集进行级联的filter等操做,只有在访问Queryset的内容的时候,Django才会真正进行数据库的访问。而多频率、复杂的数据库查询每每是性能问题最大的根源。fetch
为了方便说明,咱们定义如下model:优化
1 class A(models.Model): 2 foo = models.IntegerFiled() 3 4 class B(models.Model): 5 a = models.ForeignKey(A, related_name='bs')
关联关系中,外键的查询依然是惰性的。当咱们经过外键获取一个关联对象的时候,实际上默认获取的是关联对象的ID。这种状况适用于只须要ID而不须要实际的关联对象的场景,这点在Django的文档中有相关说明:网站
If you only need a foreign key value, use the foreign key value that is already on the object you’ve got, rather than getting the whole related object and taking its primary key.spa
不过咱们实际开发中,每每须要访问到外键对象的其余属性。若是按照默认的查询方式去遍历取值,那么会形成屡次的数据库查询,效率可想而知。code
select_related和prefetch_related正是为了解决这个问题,他们能够达到这样的目的:在查询对象集合的时候,把指定的外键对象也一并完整查询加载,避免后续的重复查询。中间件
所以,咱们能够经过下面的方式来获取B的外键关系对象A的信息:
1 b = B.objects.select_related('a').all() 2 3 for temp_b in b: 4 print temp_b.a.foo
以上方式,实际上只会触发一次数据库查询,会极大的提高查询性能。
prefetch_related效果和select_related相似,不过使用的场景不一样:
1,select_related适用于外键和多对一的关系查询;
2,prefetch_related适用于一对多或者多对多的查询。