Django prefetch_based и оптимизация производительности с помощью нескольких наборов запросов внутри цикловPython

Программы на Python
Ответить
Anonymous
 Django prefetch_based и оптимизация производительности с помощью нескольких наборов запросов внутри циклов

Сообщение Anonymous »

По сути, у меня есть несколько запросов внутри циклов, которые меня просто не устраивают. Мне нужен опыт работы с 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)):
Затем в этом цикле я просматриваю отфильтрованную подгруппу указанных выше пользователей

Код: Выделить всё

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
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Python»