You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django中正确使用prefetch_related?为何聚合查询性能差异悬殊?

问题原因

你这里用prefetch_related完全无效,因为聚合操作是在数据库层面执行的,而prefetch_related的作用是在Python层面批量预取关联模型数据、避免N+1查询——它根本不会影响聚合查询的SQL生成,反而会让Django额外执行一次PZ表的查询,拖慢整体速度。

第二条语句PZ.objects.prefetch_related('pzitem_set').aggregate(Sum('pzitem__quantity'))的实际执行逻辑是:

  1. 先查询所有PZ记录
  2. 再批量查询关联的PZItem记录(这一步是prefetch_related做的,但完全多余)
  3. 最后仍会生成一条JOIN PZ和PZItem的SQL语句计算总和,等于做了无用的额外查询,自然比直接查PZItem慢很多。
正确用法

场景1:计算所有PZItem的quantity总和

直接用第一条语句即可,这是效率最高的方式:

test = PZItem.objects.all().aggregate(Sum('quantity'))

场景2:按每个PZ分组,计算单PZ对应的PZItem数量总和

用annotate实现,同样不需要prefetch_related:

# 按PZ分组,得到每个PZ及其对应的PZItem quantity总和
pz_with_sum = PZ.objects.annotate(total_quantity=Sum('pzitem__quantity'))

场景3:确实需要预取关联数据,在Python层面手动求和

只有当你需要同时获取PZ的其他字段,且要在Python中处理关联数据时,prefetch_related才有用,但这种方式仅适合数据量小的场景,性能不如数据库层面聚合:

pzs = PZ.objects.prefetch_related('pzitem_set').all()
# Python层面求和
total = sum(item.quantity for pz in pzs for item in pz.pzitem_set.all())

总结:prefetch_related是给需要在Python中访问关联模型数据的场景设计的,数据库层面的聚合/分组查询不需要它,直接用ORM的aggregate或annotate即可。

内容的提问来源于stack exchange,提问作者skelaw

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 03:10:35