如何优化多模型Django查询,提升大数据量下的执行速度?
优化多模型得分统计的查询效率
你当前代码效率低的核心原因:
- 循环40个模型分别查询,每次都把符合日期条件的全量对象拉到Python内存里再求和,既做了40次数据库请求,又传输了大量不必要的数据。
- 没有利用数据库的聚合计算能力,把本该数据库做的计算丢给了Python。
1. 用数据库聚合替代Python求和
直接让数据库计算每个模型的总分,每次查询只返回一个数值,大幅减少数据传输量:
from django.db.models import Sum campaign_score = 0 for model in campaign_list: # 用Sum聚合函数在数据库层面完成求和 score_agg = model.objects.filter(audit_date__range=[start_date, todays_date]).aggregate(total=Sum('overall_score')) # 处理无数据的情况(此时total为None) campaign_score += score_agg['total'] or 0
2. 给日期字段加索引
每个模型的audit_date字段添加数据库索引,能显著加速日期范围查询:
在模型类的Meta中添加索引:
class ExampleModel(models.Model): audit_date = models.DateField() overall_score = models.FloatField() # 其他字段... class Meta: indexes = [models.Index(fields=['audit_date'])]
执行迁移生效:python manage.py makemigrations && python manage.py migrate
3. 针对「每月平均分」的精准优化
如果你的核心需求是按月份统计平均分,直接用数据库分组聚合,一次性拿到每个月的总分和数据量,再计算平均:
from django.db.models import Sum, Count from django.db.models.functions import ExtractMonth, ExtractYear monthly_data = [] for model in campaign_list: # 按年、月分组,统计每组的总分和数据量 model_monthly = model.objects.filter(audit_date__range=[start_date, todays_date]).annotate( year=ExtractYear('audit_date'), month=ExtractMonth('audit_date') ).values('year', 'month').annotate( total_score=Sum('overall_score'), record_count=Count('id') ).order_by('year', 'month') monthly_data.extend(model_monthly) # 合并不同模型的同月数据,计算最终平均分 final_monthly_avg = {} for item in monthly_data: key = (item['year'], item['month']) if key not in final_monthly_avg: final_monthly_avg[key] = {'total': 0, 'count': 0} final_monthly_avg[key]['total'] += item['total_score'] or 0 final_monthly_avg[key]['count'] += item['record_count'] or 0 # 输出结果 for (year, month), stats in final_monthly_avg.items(): if stats['count'] > 0: avg = stats['total'] / stats['count'] print(f"{year}年{month}月 平均分:{avg:.2f}")
进阶建议:合并模型(如果结构一致)
如果这40个模型的字段完全相同,建议改成单表+类型字段的结构(比如新增campaign_type字段区分不同业务类型),这样只需要一次查询就能完成所有统计,效率会提升数十倍。
内容的提问来源于stack exchange,提问作者Ibrahim Khan
相关产品推荐
相关产品推荐

