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

优化Django反向查询:prefetch_related仍触发额外查询的解决方案

解决Django prefetch_related后仍触发额外查询的问题

问题原因分析

你遇到的情况是:虽然使用了prefetch_related('eir')预取关联数据,但调用chassis.first().eir.all()时依然触发了新的数据库查询。核心原因是:

  • 执行chassis = Chassis.objects.prefetch_related('eir')后,输入chassis会触发QuerySet求值,此时Django查询前21条Chassis并批量预取对应Eir数据(WHERE chassis_id IN (1292,104))。
  • 但默认调用instance.eir.all()时,会生成新的QuerySet实例,在部分场景下会绕过预取缓存,重新发起单条Chassis的Eir查询。而你在DRF的to_representation中使用instance.eir.all().last().id,会导致每条Chassis都触发一次额外查询,形成N+1问题。

解决方案

方案1:用Prefetch预取排序后的关联数据

通过Prefetch指定预取时的排序规则,让预取的Eir按需求排列,后续直接从缓存取结果,避免额外查询:

from django.db.models import Prefetch

# 查询时预取每个Chassis的Eir,并按id降序排列(方便快速取最新一条)
chassis_qs = Chassis.objects.prefetch_related(
    Prefetch('eir', queryset=Eir.objects.order_by('-id'))
)

在DRF的to_representation中直接使用缓存数据:

def to_representation(self, instance):
    ret = super().to_representation(instance)
    eirs = instance.eir.all()
    ret['eir'] = eirs[0].id if eirs else None
    return ret

此时instance.eir.all()会直接调用预取的缓存,不会触发新的数据库查询。

方案2:用Subquery注解最新Eir的ID(更高效)

如果仅需获取每个Chassis对应的最新Eir的ID,不需要预取所有Eir记录,推荐用Subquery直接注解字段,一次查询搞定所有数据:

from django.db.models import Subquery, OuterRef

# 子查询:获取每个Chassis对应的最新Eir的ID
latest_eir_subquery = Eir.objects.filter(
    chassis=OuterRef('pk')
).order_by('-id').values('id')[:1]

# 给每个Chassis添加latest_eir_id注解字段
chassis_qs = Chassis.objects.annotate(
    latest_eir_id=Subquery(latest_eir_subquery)
)

在DRF的to_representation中直接使用注解字段:

def to_representation(self, instance):
    ret = super().to_representation(instance)
    ret['eir'] = instance.latest_eir_id
    return ret

这种方式仅需两次查询(一次查Chassis,一次查所有最新Eir的ID),比预取所有Eir数据更高效,尤其适合Chassis关联大量Eir记录的场景。

验证测试

按方案1修改查询后,在Django CLI重新测试:

>>> chassis = Chassis.objects.prefetch_related(Prefetch('eir', queryset=Eir.objects.order_by('-id')))
>>> chassis  # 触发两次查询:Chassis列表和批量预取Eir
>>> chassis.first().eir.all()  # 直接从缓存读取,无新查询

此时数据库日志不会出现第三次查询,符合预期。

内容的提问来源于stack exchange,提问作者Dean Christian Armada

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 07:42:44