バルクデータベースエントリを効率的に作成できますか?

私は Inquiry オブジェクトの大きな(300 +以上の)リストの Activty オブジェクトを作成しようとしています。 1つの ModelForm がポストバックされており、別のインスタンスを作成して GenericForeignKey を介して Inquiry にアタッチする必要があります。いくつかのコードに行きましょう:

models.py:

class InquiryEntry(models.Model):
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField() 
    entry = generic.GenericForeignKey('content_type', 'object_id')

class Inquiry(models.Model):
    entries = models.ManyToManyField('InquiryEntry')
    # And many more fields.
    def add_entry(self, obj):
        entry = self.entries.create(entry=obj)
        self.save()
        return entry

class Activity(models.Model):  
    ts = models.DateTimeField(auto_now_add=True)                  
    due_date = models.DateField(auto_now=False)
    ## And many more fields.

views.py:

def bulk_create_activities(request):
    activity_form = ActivityForm()
    if request.method == "POST":
        activity_form = ActivityForm(request.POST)
        if activity_form.is_valid():    
            pks = [int(x) for x in request.POST.get('pks', '').split(',')]
            for inquiry in Inquiry.objects.filter(pk__in=pks):
                instance = ActivityForm(request.POST).save()
                inquiry.add_entry(instance)     
                inquiry.save()  

私が探しているのは、これらをデータベースに挿入する方法です。要求をより速く処理できるように、1回のパスで行うことが望ましいです。このアプリケーションは複数のデータベースベンダーに配備されているため、データベースレベルに落とさないことをお勧めしますが、これが唯一の方法であれば、そうしてください(MySQLとPostgresの例はすばらしいでしょう)。


Note: I know that there is a bulk_create in the development version, but that is out of the question until there is a stable release.

10

5 答え

単純に for をトランザクション構造で囲んでみましたか?エントリが一括して一度にディスクに書き込まれるため、Commit-on-successトランザクションでは大量のスピードアップが発生する可能性があるため、DBMSは各アイテムの後にfsync()を停止する必要はありません。

Implementing transactions in recent versions of django is snappy, check out https://docs.djangoproject.com/en/dev/topics/db/transactions/#controlling-transaction-management-in-views

3
追加された
良いアイデアのようだが、パフォーマンスはあまり変わらない。 5-10の活動では、約5%のスピードアップがありました。 100で10%のスピード低下。
追加された 著者 Jack M.,
ポインタありがとう。これは素晴らしい新機能です。
追加された 著者 AgDude,

にドロップする必要があるかもしれません。 DB-API を使用し、cursor.executemany()を使用します。詳細については、 PEP 249 を参照してください。

1
追加された

これは一括処理を効率化するものではありませんが、提出されたデータに基づいて瞬時にお問い合わせに返信する必要がない場合(モデル名に基づいていると仮定しています) Celeryのようなタスクキューのための完璧な仕事のように。

ユーザーは超高速応答を得ることができ、セーラーワーカーは余暇でそれを刈り取ることができます。 1.4が安定したら、in_bulk :)をチェックしてください:)

私はまた、データベースにとらわれない岩石の固体メソッドに興味があるだろうが、あなたの状況に応じて、これは許容される解決策かもしれない。

ここで答えを見ています...

0
追加された

Take a look at http://people.iola.dk/olau/python/bulkops.py

これは、単一の照会を実行するinsert_manyおよびupdate_many関数を提供します。著者が指摘したように、Pythonで多対多の関係のpkのマニュアル簿記を行う必要がありますが、一度問題が解決したら、 Inquiry> InquiryEntry

0
追加された

いくつかのサンプルデータに対して生成されるSQL djangoを見て、いくつかのヒント(異なるデータベースシステムを含む)を得ることができるかもしれません。サーバーをデバッグモードで実行すると、すべてのクエリがログに記録されます。あなたはそれらを介して検査することもできます

>>> from django.db import connection
>>> connection.queries
0
追加された