Django的 select_related 和 prefetch_related 函数对 QuerySet 查询的优化

问题描述:

对于Django中的“N+1”问题,如:

posts = Post.objects.all()
for post in posts:  # 产生1次数据库查询所有的post
	print(post.owner.username)  # 产生1次额外的外键数据库查询
	print(post.category.name)  # 产生1次额外的外键数据库查询

这样会导致线性的SQL查询,如果对象数量N太多,每个对象中有k个外键字段的话,就会导致Nk+1次SQL查询。在本例中,因为有N个post对象,每个对象有2个外键,就导致了N2+1次SQL查询,这个1次是为了获取所有的post。

问题解决:

1、使用select_related接口,针对一对一外键。

# Django 1.7版本之前,只能使用
Post.objects.all().select_related('category', 'owner')
# Django 1.7版本之后,也可以使用链式操作(即上下两种方式都可以):
Post.objects.all().select_related('category').select_related('owner')
for post in posts:  # 产生1次数据库查询所有的post,category和owner也会一次性查询出来
	print(post.owner.username)  
	print(post.category.name) 

所以上面的代码,总共只会产生一次sql查询。
2、针对多对多外键的数据,可以使用prefetch_related接口来解决:

Post.objects.all().prefetch_related('tag')
for post in posts:  # 产生两次sql查询,分别查询所有的post和对应的tag
	print(post.tag.all()) 

所以上面的代码,总共只会产生2次sql查询。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值