实际上,我在循环中有多个查询,但我对此并不满意。我想知道是否有人具有prefetch_related
其他 Django 查询构造优化方面的专业知识,能够在这个问题上为我提供帮助。
我开始:
users = User.objects.filter(organisation=organisation).filter(is_active=True)
然后,我从某个日期“ start_date
”开始,在所有日子里开始循环:
for date in (start_date + datetime.timedelta(n) for n in range((datetime.datetime.now().replace(tzinfo=pytz.UTC) - start_date).days + 1)):
然后我在这个循环中遍历上面的过滤子集users
for date in (start_date + datetime.timedelta(n) for n in range((datetime.datetime.now().replace(tzinfo=pytz.UTC) - start_date).days + 1)):
for user in users.filter(created_date__lte=date).iterator():
好的,首先,有没有办法优化这个?
是什么让一些铁杆 Django 人失去了他们的束缚,我在另一个循环中完成了上述所有操作!
for survey in Survey.objects.all().iterator():
for date in (start_date + datetime.timedelta(n) for n in range((datetime.datetime.now().replace(tzinfo=pytz.UTC) - start_date).days + 1)):
for user in users.filter(created_date__lte=date).iterator():
在最后一个循环中,我执行了最后一个查询过滤器:
survey_result = SurveyResult.objects.filter(survey=survey, user=user, created_date__lte=date).order_by('-updated_date')[0]
我这样做是因为我觉得我需要准备好过滤用户、调查和日期变量......
我已经开始考虑 prefetch_related 和 Prefetch 对象。我已经查阅了文档,但我似乎无法理解如何将其应用于我的情况。
实际上,查询花费的时间太长了。对于平均 1000 名用户、4 次调查和大约 30 天,此查询需要 1 分钟才能完成。
理想情况下,我想剃掉 50%。再好不过了,我会非常高兴。我还希望减少数据库服务器上的负载,因为此查询可能在不同的组织中运行多次。
任何有关如何在循环内的循环内组织此类可怕查询的专家提示将不胜感激!
完整的“浓缩”最小可行片段:
users = User.objects.filter(organisation=organisation).filter(is_active=True)
datasets = []
for survey in Survey.objects.all():
data = []
for date in (start_date + datetime.timedelta(n) for n in range((datetime.datetime.now().replace(tzinfo=pytz.UTC) - start_date).days + 1)):
total_score = 0
participants = 0
for user in users.filter(created_date__lte=date):
participants += 1
survey_result = SurveyResult.objects.filter(survey=survey, user=user, created_date__lte=date).order_by('-updated_date')[0]
total_score += survey_result.score
# An average is calculated from the total_score and participants and append to the data array.:
# Divide catches divide by zero errors.
# Round will round to two decimal places for front end readability.
data.append(
round(
divide(total_score, participants), 2
)
)
datasets.append(data)
********* 附录:*********
因此,除了@dirkgroten 的回答,我目前正在使用:
for survey in Survey.objects.all():
results = SurveyResult.objects.filter(
user__in=users, survey=survey, created_date__range=date_range
).values(
'survey',
'created_date',
).annotate(
total_score=Sum('normalized_score'),
participants=Count('user'),
average_score=Avg('normalized_score'),
).order_by(
'created_date'
)
for result in results:
print(result)
因为我(“认为我”)需要对每个 QuerySet 进行调查细分。
我还有其他可用的优化吗?