Я начинаю с:
Код: Выделить всё
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)):
Код: Выделить всё
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)
Доступны ли мне какие-либо другие варианты оптимизации?
Подробнее здесь: https://stackoverflow.com/questions/573 ... rysets-wit
Мобильная версия