如何优化Django查询以提升性能?避免循环内查询操作
Django查询优化:避免循环内查询获取每个活跃Item的最后一条Price记录
你的代码存在典型的N+1查询问题——先查所有活跃Item,再循环每个Item单独拉取对应的最后一条Price,Item数量多的时候数据库请求会爆炸,性能拉胯。下面是两种优化方案,都能把查询次数压缩到2次:
方案1:用Subquery子查询(推荐)
假设Price模型默认按id递增排序(last()本质是取id最大的那条),如果你的排序字段是created_at这类时间字段,把order_by('-id')改成order_by('-created_at')就行。
只获取Price的单个字段(比如价格值)
from django.db.models import Subquery, OuterRef # 子查询:获取当前Item对应的最后一条Price latest_price_subquery = Price.objects.filter(item_id=OuterRef('id')).order_by('-id')[:1] # 查询活跃Item并附加对应的最新价格 active_items = Items.objects.filter(active=True).annotate( latest_price=Subquery(latest_price_subquery.values('price')) # 替换成你需要的字段,比如price、created_at ) # 提取价格列表(过滤掉没有Price记录的Item) price_list = [item.latest_price for item in active_items if item.latest_price]
获取完整的Price对象
如果需要拿到整个Price实例,调整子查询结合预取:
from django.db.models import Subquery, OuterRef from django.db.models.query import Prefetch latest_price_subquery = Price.objects.filter(item_id=OuterRef('id')).order_by('-id')[:1] active_items = Items.objects.filter(active=True).annotate( latest_price_id=Subquery(latest_price_subquery.values('id')) ).prefetch_related( Prefetch( 'price_set', queryset=Price.objects.filter(id__in=Subquery(latest_price_subquery.values('id'))), to_attr='latest_price' ) ) # 提取完整的Price对象列表 price_list = [item.latest_price[0] for item in active_items if item.latest_price]
方案2:通过Max聚合关联
如果Price的id是自增的,最后一条记录就是id最大的,先给每个Item标注最大Price id,再批量查询:
from django.db.models import Max # 给每个活跃Item标注对应的最大Price id active_items = Items.objects.filter(active=True).annotate( max_price_id=Max('price__id') ) # 收集所有有效Price id,过滤掉没有Price记录的Item valid_price_ids = [item.max_price_id for item in active_items if item.max_price_id] # 批量查询Price并构建映射字典 price_map = {price.id: price for price in Price.objects.filter(id__in=valid_price_ids)} # 生成最终的Price列表 price_list = [price_map[item.max_price_id] for item in active_items if item.max_price_id]
这两种方案都只需要2次数据库请求,彻底解决循环查询的性能问题。
内容的提问来源于stack exchange,提问作者Puneet Shekhawat
相关产品推荐
相关产品推荐

