Эффективное обновление большого количества записей на основе поля в этой записи с помощью Django
У меня есть около миллиона записей Comment, которые я хочу обновить на основе поля body этого комментария. Я пытаюсь понять, как сделать это эффективно. На данный момент мой подход выглядит следующим образом:
update_list = []
qs = Comments.objects.filter(word_count=0)
for comment in qs:
model_obj = Comments.objects.get(id=comment.id)
model_obj.word_count = len(model_obj.body.split())
update_list.append(model_obj)
Comment.objects.bulk_update(update_list, ['word_count'])
Однако в процессе миграции все зависает и, похоже, прерывается. Есть ли у кого-нибудь предложения, как я могу это сделать?
Нелегко определить объем памяти объекта Django, но абсолютный минимум - это объем пространства, необходимый для хранения всех его данных. Я предполагаю, что вам может не хватать памяти, и вы перегружаете страницы.
Вероятно, вы хотите работать партиями, скажем, по 1000 объектов за раз. Используйте Queryset slicing, который возвращает другой queryset. Попробуйте что-нибудь вроде
BATCH_SIZE = 1000
start = 0
base_qs = Comments.objects.filter(word_count=0)
while True:
batch_qs = base_qs[ start: start+BATCH_SIZE ]
start += BATCH_SIZE
if not batch_qs.exists():
break
update_list = []
for comment in batch_qs:
model_obj = Comments.objects.get(id=comment.id)
model_obj.word_count = len(model_obj.body.split())
update_list.append(model_obj)
Comment.objects.bulk_update(update_list, ['word_count'])
print( f'Processed batch starting at {start}' )
Каждый цикл будет освобождать место, занятое предыдущим циклом, когда он заменяет batch_qs и update_list. Оператор print позволит вам наблюдать, как он продвигается с, надеюсь, приемлемой, регулярной скоростью!
Предупреждение - я никогда не пробовал это делать. Мне также интересно, будут ли нарезка и фильтрация хорошо сочетаться друг с другом, или нужно использовать
base_qs = Comments.objects.all()
...
while True:
batch_qs = base_qs[ start: start+BATCH_SIZE ]
....
for comment in batch_qs.filter(word_count=0) :
Таким образом, вы прокладываете свой путь через строки во всей таблице DB и извлекаете подмножество каждого фрагмента, которое нуждается в обновлении. Это кажется "более безопасным". Кто-нибудь знает наверняка?