QuerySet
QuerySet是惰性的——创建QuerySet的行为不涉及任何数据库活动。 只有在拿结果的时候才会连接数据库
a = TB.objects.all() b = a.filter(id=1) print(b)
只有在执行 print(b) 的时候才会连接数据库
select_related
返回一个QuerySet,当执行它的查询时,它沿着外键关系查询关联的对象的数据。它会生成一个复杂的查询并引起性能的损耗,但是在以后使用外键关系时将不需要数据库查询。
对于一对一字段(OneToOneField)和外键字段(ForeignKey),可以使用
select_related 来对QuerySet进行优化,在对QuerySet使用select_related()函数后,Django会获取相应外键对应的对象,从而在之后需要的时候不必再查询数据库了。# 连接数据库 e = Entry.objects.get(id=5) # 再次连接数据库以获取相关的Blog对象 b = e.blog
# 连接数据库
e = Entry.objects.select_related('blog').get(id=5)
# 没有进入数据库,因为e.blog已经预填充在前面的查询中。
b = e.blog
select_related主要针一对一和多对一关系进行优化。select_related使用SQL的JOIN语句进行优化,通过减少SQL查询的次数来进行优化、提高性能。- 可以通过可变长参数指定需要
select_related的字段名。也可以通过使用双下划线“__”连接字段名来实现指定的递归查询。没有指定的字段不会缓存,没有指定的深度不会缓存,如果要访问的话Django会再次进行SQL查询。 - 也可以通过
depth参数指定递归的深度,Django会自动缓存指定深度内所有的字段。如果要访问指定深度外的字段,Django会再次进行SQL查询。 - 也接受无参数的调用,Django会尽可能深的递归查询所有的字段。但注意有Django递归的限制和性能的浪费。
prefetch_related
这允许它预取多对多和多对一对象,因为它们不能使用select_related来完成。
select_related主要是执行跨表操作,而prefetch_related不是跨表操作,而是对每个表分别执行SQL查询(Django内部在您使用时自动会帮你像跨表操作一样连接起来),从而减少跨表查询,提升性能。
小结
- 因为
select_related()总是在单次SQL查询中解决问题,而prefetch_related()会对每个相关表进行SQL查询,因此select_related()的效率通常比后者高。 - 鉴于第一条,尽可能的用
select_related()解决问题。只有在select_related()不能解决问题的时候再去想prefetch_related()。 - 你可以在一个QuerySet中同时使用
select_related()和prefetch_related(),从而减少SQL查询的次数。 - 只有
prefetch_related()之前的select_related()是有效的,之后的将会被无视掉。
浙公网安备 33010602011771号