使用Django Prefetch对象时为何会生成多个关联对象查询?
Django Prefetch对象引发N+1查询的原因及修复方案
问题核心很明确:你在Prefetch的子查询里用了.only("id"),但Django需要**关联外键字段shift_id**来建立Schedule和Shift的关联关系,这个字段没被包含在预取的字段列表里,导致后续访问shifts时触发N+1查询。
具体原因
当你用only("id")预取Shift时,批量查询出来的Shift对象只存储了id值,没有shift_id(关联Schedule的外键)。Django要把Shift和对应的Schedule关联起来时,找不到必要的外键数据,只能逐个查询Shift对象获取shift_id,这就产生了额外的N次查询。
修复方案
在Prefetch的queryset里,把关联外键shift_id加入only的字段列表即可:
Schedule.objects.prefetch_related( Prefetch( "shifts", queryset=Shift.objects.filter( state__in=[States.COMPLETED, States.PENDING] ) .order_by("assigned_at", "priority", "order") .only("id", "shift_id"), # 新增shift_id字段 ) ).only("id")
为什么这样有效?
加上shift_id后,批量预取的Shift对象已经包含了关联Schedule所需的外键信息,Django可以直接在内存中完成Schedule和Shift的匹配,不会再触发额外的SQL查询,回到预期的2次查询的优化效果。
内容的提问来源于stack exchange,提问作者hancho
相关产品推荐
相关产品推荐

