Django中bulk_update与update的性能优势及查询次数疑问
Django批量更新性能对比与查询次数疑问
问题背景
我有这段代码:
Subscription.objects.filter(id__in=[subscription.id for subscription in subscriptions]).update(renewal_notification_sent=True)
想知道换成下面的写法有没有性能优势:
updatable_subscriptions = [] subs = Subscription.objects.filter(id__in=[subscription.id for subscription in subscriptions]) for sub in subs: sub.renewal_notification_sent = True updatable_subscriptions.append( subs ) # then Subscription.objects.bulk_update(updatable_subscriptions, ["renewal_notification_sent"])
另外,调用filter后再执行update会产生两次数据库查询吗?
解答
1. 性能对比:哪种写法更好?
你的第二种写法没有性能优势,反而更差,原因很直接:
- 第一种写法是直接在数据库层面执行单条UPDATE语句,所有更新操作一次完成,只发起一次数据库请求,效率最高。
- 第二种写法先执行了一次SELECT查询,把所有符合条件的
Subscription对象拉到内存里,接着循环修改内存中的对象属性,最后调用bulk_update。这里不仅多了一次查询开销,数据量大的时候还会占用更多内存;而且bulk_update默认会分批次处理(每批次最多1000条),生成多条UPDATE语句,整体开销远大于第一种写法。
另外你的第二种写法还有个小bug:updatable_subscriptions.append(subs)会把整个QuerySet作为单个元素塞进列表,而bulk_update需要的是对象列表,正确的写法应该直接传subs或者list(subs),但就算修正了这个问题,性能还是不如第一种写法。
2. filter后执行update的查询次数
不会产生两次查询。Django的QuerySet是惰性求值的——调用filter只是构建了查询条件,并不会立刻执行SQL。只有当你调用update()时,才会把filter条件和update操作合并成一条完整的UPDATE语句发送给数据库,全程只执行一次数据库查询。
比如你写的代码最终会生成类似这样的SQL:
UPDATE subscription SET renewal_notification_sent = True WHERE id IN (...);
内容的提问来源于stack exchange,提问作者E_K
相关产品推荐
相关产品推荐

