在Django中聚合save()吗?

56 投票
4 回答
43887 浏览
提问于 2025-04-16 02:14

我正在使用Django和sqlite数据库,但写入性能有点问题。将来我可能会换成一个“真正的”数据库,但目前我只能用sqlite。我觉得我的写入性能问题可能是因为我创建了很多行数据,每次我调用save()的时候,数据库都会锁定、解锁并同步到磁盘上。

我该如何把很多个save()操作合并成一次数据库操作呢?

4 个回答

18

我觉得你要找的方法是这个:https://docs.djangoproject.com/en/dev/ref/models/querysets/#bulk-create

以下是从文档中复制的代码:

Entry.objects.bulk_create([
    Entry(headline='This is a test'),
    Entry(headline='This is only a test'),
])

在实际使用中,它看起来会是这样的:

my_entries = list()
for i in range(100):
    my_entries.append(Entry(headline='Headline #'+str(i))

Entry.objects.bulk_create(my_entries)

根据文档,这个方法只会执行一次查询,不管列表有多大(在SQLite3中最多支持999个项目),而atomic装饰器就不能这样。

这里有一个重要的区别。根据提问者的问题,听起来他想要的是批量创建而不是批量保存atomic装饰器是保存时最快的解决方案,但不是创建时的最快方案。

81

在Django 1.6版本中新增了一个叫做 atomic 的功能,它是一个简单的接口,用来控制数据库的事务。

根据文档的说明,atomic可以作为一个 装饰器 使用:

from django.db import transaction

@transaction.atomic
def viewfunc(request):
    # This code executes inside a transaction.
    do_stuff()

也可以作为一个 上下文管理器 使用:

from django.db import transaction

def viewfunc(request):
    # This code executes in autocommit mode (Django's default).
    do_stuff()

    with transaction.atomic():
        # This code executes inside a transaction.
        do_more_stuff()

之前的 django.db.transaction 函数,比如 autocommit()commit_on_success()commit_manually() 已经被弃用,并将在Django 1.8中移除。

84

更新:commit_on_success 已经不再使用,并在 Django 1.8 中被移除了。请改用 transaction.atomic。具体可以参考 Fraser Harris 的 回答

其实这比你想象的要简单得多。在 Django 中,你可以使用事务。这些事务可以把多个数据库操作(特别是保存、插入和删除)合并成一个操作。我发现最简单的用法是 commit_on_success。基本上,你只需要把数据库的保存操作放到一个函数里,然后使用 commit_on_success 装饰器。

from django.db.transaction import commit_on_success

@commit_on_success
def lot_of_saves(queryset):
    for item in queryset:
        modify_item(item)
        item.save()

这样做会大大提高速度。如果有任何操作失败,你还可以享受到回滚的好处。如果你有数百万个保存操作,可能需要使用 commit_manuallytransaction.commit() 来分批提交,但我很少需要这样做。

撰写回答