一、select_related查询优化
select_related通过多表jong关联查询,它将“跟随”外键关系,在执行查询时选择额外的相关对象数据,导致一个更复杂的单一查询,但意味着以后使用外键关系将不需要数据库查询。
下面的例子说明了普通查找和 select_related() 查找之间的区别。下面是标准的查询:
# Hits the database.
e = Entry.objects.get(id=5)
# Hits the database again to get the related Blog object.
b = e.blog
这里是 select_related 查找:
# Hits the database.
e = Entry.objects.select_related('blog').get(id=5)
# Doesn't hit the database, because e.blog has been prepopulated
# in the previous query.
b = e.blog
二、prefetch_related查询优化
与 select_related 有类似的目的,二者都是为了阻止因访问相关对象而引起的数据库查询,减少SQL查询对数量,但策略却完全不同。
select_related 的工作方式是创建一个 SQL 连接,并在 SELECT 语句中包含相关对象的字段。通过join语句,在SQL查询内解决问题,但是仅限于单值关系——外键和一对一。对于多对多关系,使用SQL语句,会导致join得到的表将会很长,使SQL语句运行时间增加和内存占用增加
prefetch_related 则对每个关系进行单独的查找,并在 Python 中进行“joining”。这使得它除了支持 select_related 的外键和一对一关系外,还可以预取多对多和多对一的对象,这是用 select_related 无法做到的。它还支持 GenericRelation 和 GenericForeignKey 的预取。
总结
1、select_related是通过join来关联多表,一次获取数据,存放在内存中,但如果关联的表太多,会严重影响数据库性能。
2、prefetch_related是通过分表,先获取各个表的数据,存放在内存中,然后通过Python处理他们之间的关联。
3、select_related()的效率要高于prefetch_related()。因此,最好在能用select_related()的地方尽量使用它,也就是说,对于ForeignKey字段,避免使用prefetch_related()。
因为 select_related() 总是在单次 SQL 查询中解决问题,而 prefetch_related() 会对每个相关表进行 SQL 查询,因此 select_related() 的效率通常比后者高
4、可以在调用prefetch_related之前调用select_related,并且Django会按照你想的去做:先select_related,然后利用缓存到的数据prefetch_related。然而一旦prefetch_related已经调用,select_related将不起作用。