django - 使用 Django 根据记录中的字段高效更新大量记录

标签 django database django-models orm django-migrations

我有大约一百万条 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 ,它返回另一个查询集。尝试类似的事情

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时都会释放前一次所占用的空间。打印语句将允许您以希望可以接受的正常速度观察它的进展!

警告 - 我从未尝试过这个。我还想知道切片和过滤是否可以很好地配合,或者是否应该使用

base_qs = Comments.objects.all()
...
while True:
    batch_qs = base_qs[ start: start+BATCH_SIZE ]
    ....
    for comment in batch_qs.filter(word_count=0) : 

因此,您可以对整个数据库表中的行进行切片,并检索需要更新的每个切片的子集。这感觉“更安全”。有人确切知道吗?

关于django - 使用 Django 根据记录中的字段高效更新大量记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71269858/

相关文章:

python - Django .aggregate() 在 .annotate() 上

Django模型选择字段: Huge List of choices

database - IBM Notes 数据库 - 慢

php - Zendframework Rowset 按键选择

mysql - 连接数百万行表的性能

python - 如何调用 python 声明属性模式

python - 对于 Django 中的 1 对 1 关系,两个模型是否共享 id?

django - post_delete/pre_delete 信号未针对特定发件人触发

python - 如何在 Django 中记录所有外发电子邮件?

django - 将 SSL 添加到 Django 应用程序、Ubuntu 16+、DigitalOcean