python 在Django中聚合保存()?

hrirmatl  于 2022-12-25  发布在  Python
关注(0)|答案(4)|浏览(103)

我使用的Django有一个sqlite后端,写性能是一个问题。我可能在某个阶段升级到一个“合适的”数据库,但目前我还停留在sqlite上。我认为我的写性能问题可能与我创建大量行有关,大概每次我save()一行时,它都会锁定、解锁和同步磁盘上的数据库。
如何将大量save()调用聚合到单个数据库操作中?

col17t5w

col17t5w1#

EDITED:commit_on_success已过时,在Django 1.8中已被移除。请使用transaction.atomic。请参阅Fraser Harris的answer
实际上这比你想象的要容易。你可以在Django中使用transactions。这些批量数据库操作(特别是保存、插入和删除)合并成一个操作。我发现最容易使用的是commit_on_success。本质上你可以把数据库保存操作 Package 成一个函数,然后使用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()以块的形式提交它们,但我很少需要这样做。

2nc8po8w

2nc8po8w2#

Django 1.6的新特性是原子的,一个简单的API来控制数据库事务。
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中移除。

c86crjj0

c86crjj03#

我想这就是你要找的方法: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装饰器来说是不可能的。
这里有一个重要的区别。从OP的问题中听起来,他试图 * 批量创建 * 而不是 * 批量保存 *。atomic装饰器是 * 保存 * 的最快解决方案,但不是 * 创建 *。

zazmityj

zazmityj4#

"如何将大量save()调用聚合到单个数据库操作中?"
你不需要这样做。Django已经为你管理了一个缓存。你不能通过尝试保存来改善它的DB缓存。
"写入性能问题可能与创建大量行有关"
正确。
SQLite是相当慢的。这就是它的方式。查询比大多数其他数据库的快。写是相当慢。
考虑更严重的架构更改,您是否在Web事务期间加载行(例如,批量上载文件并从这些文件加载DB)?
如果你在一个web事务中进行批量加载,停止。你需要做一些更聪明的事情。使用celery或其他"批处理"工具在后台进行加载。
我们尝试将自己限制在Web事务中的文件验证,并在用户不等待HTML页面时执行加载。

相关问题