Django中如何高效获取每个Medecin对应的最新Visite记录
Django查询每个医生对应的最新拜访记录优化方案
你当前的写法属于典型的N+1查询问题:1次查询拉取所有医生数据,之后遍历每个医生时都要单独发起1次查询拉取对应拜访记录,医生数量多时性能会指数级下降。以下是两种高效实现方案:
方案1:通用子查询方案(兼容所有数据库,仅需2次查询)
使用Django ORM的Subquery注解实现,不需要依赖特定数据库,适用范围最广:
from django.db.models import OuterRef, Subquery # 构造子查询:匹配外部医生ID,按关联报告的创建时间倒序,取最新1条拜访记录的主键 latest_visite_sub = Visite.objects.filter( medecin_id=OuterRef('pk') ).order_by('-rapport__added').values('pk')[:1] # 给所有医生注解最新拜访记录ID,过滤掉没有拜访记录的医生 medecins = Medecin.objects.annotate( latest_visite_id=Subquery(latest_visite_sub) ).filter(latest_visite_id__isnull=False) # 一次性拉取所有最新拜访记录 last_visites = Visite.objects.filter(id__in=medecins.values_list('latest_visite_id', flat=True))
如果你的拜访记录主键是自增的、插入顺序等于时间顺序,也可以直接按-pk排序,省略关联报告的查询,性能更高:
latest_visite_sub = Visite.objects.filter( medecin_id=OuterRef('pk') ).order_by('-pk').values('pk')[:1]
方案2:PostgreSQL专属方案(仅需1次查询,性能最高)
如果你使用PostgreSQL作为数据库,可以直接用distinct的专属语法,一次查询拿到所有结果:
last_visites = Visite.objects.order_by( 'medecin_id', '-rapport__added' ).distinct('medecin_id')
额外优化建议
- 如果需要同时获取医生和对应拜访记录的信息,可以在查询Visite时加上
select_related('medecin'),一次查询把关联的医生数据也拉取回来,避免后续额外请求:last_visites = Visite.objects.select_related('medecin').order_by( 'medecin_id', '-rapport__added' ).distinct('medecin_id') - 建议给Visite表的
medecin_id和rapport_id加联合索引,可大幅提升查询速度。 - 你原来的写法没有处理医生没有拜访记录的情况,直接取
[-1]会抛出IndexError,上述方案默认过滤掉了无拜访记录的医生,如需保留可以删除filter(latest_visite_id__isnull=False)条件。
内容的提问来源于stack exchange,提问作者Blue
相关产品推荐
相关产品推荐

