web-dev-qa-db-ja.com

Djangoでsave()を集約していますか?

私はDjangoをsqliteバックエンドで使用しています。書き込みパフォーマンスが問題です。ある段階で「適切な」dbに変更される可能性がありますが、今のところsqliteで動けなくなっています。私の書き込みパフォーマンスの問題は、おそらく私が多数の行を作成しているという事実に関連していると思います。おそらく、私がsave() oneを実行するたびに、ディスク上のDBがロック、ロック解除、同期されます。

多数のsave()呼び出しを1つのデータベース操作に集約するにはどうすればよいですか?

46
kdt

編集:_commit_on_success_は廃止され、Django 1.8で削除されました。代わりに_transaction.atomic_を使用してください。FraserHarrisの answer を参照してください。

実際、これはあなたが考えるよりも簡単です。 Djangoでは transactions を使用できます。これらのバッチデータベース操作(具体的には、保存、挿入、削除)を1つの操作にまとめます。最も使いやすいのは_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_manually_とtransaction.commit()を使用してブロックでそれらをコミットする必要があるかもしれませんが、私はめったにそれを必要としませんでした。

お役に立てれば幸いです。

意志

66
JudoWill

Django 1.6 is atomic、DBトランザクションを制御するシンプルなAPI の時点での新機能)==。ドキュメントから逐語的にコピー:

atomicは decorator として両方使用できます:

_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で削除されます。

57
Fraser Harris

これはあなたが探している方法だと思います: 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の質問から、彼はbulk saveではなくbulk createを試行されているようです。 atomicデコレータはsavingの最速のソリューションですが、creatingのソリューションではありません。

7
Chris Conlan

「多数のsave()呼び出しを1つのデータベース操作に集約するにはどうすればよいですか?」

する必要はありません。 Djangoは既にキャッシュを管理しています。保存をいじくりまわしてDBのキャッシュを改善することはできません。

「書き込みパフォーマンスの問題は、おそらく私が大量の行を作成しているという事実に関連しています」

正しい。

SQLiteはかなり遅いです。そういうものだ。クエリは他のほとんどのDBよりも高速です。書き込みはかなり遅いです。

より深刻なアーキテクチャの変更を検討してください。 Webトランザクション中に行をロードしていますか(つまり、ファイルを一括アップロードし、それらのファイルからDBをロードしていますか)?

Webトランザクション内で一括読み込みを実行している場合は、停止してください。もっと賢くする必要があります。 celery を使用するか、他の「バッチ」機能を使用して、バックグラウンドでロードを実行します。

私たちは、Webトランザクションでのファイル検証に制限し、ユーザーがHTMLのページを待機していないときにロードを実行しようとします。

0
S.Lott