5

2 つのデータベースを同期するスクリプトを作成しています。データベースにはツリーとして保存する必要があるデータがあるため、新しい DB にはdjango-mpttを使用します。DB を同期するとき、古い DB から新しいデータを選択し、それを新しい DB に保存する必要があります。

新しいノードをツリーに追加するためのより良い方法があるかどうか知りたいですか? 次のようになります。

...
# Add new data to DB
for new_record in new_records:
    # Find appropriate parent using data in 'new_record'
    parent = get_parent(new_record)

    # Create object which should be added using data in 'new_record'
    new_node = MyMPTTModel(...)
    new_node.insert_at(parent, save = True)
    # Similar to:
    # new_node.insert_at(parent, save = False)
    # new_node.save()

しかし、動作が非常に遅いです。insert_at(..., save = True)メソッドdjango-mpttを呼び出すたびに新しいノードをDBに書き込み、すでにDBにあるレコードのキーを left変更する必要があるため、このように機能すると思います。right

django-mptt呼び出すたびにクエリを変更し、insert_at呼び出したときにすべての変更をまとめて適用する方法はありますsaveか? または、実行時間を短縮する他の方法を知っていますか?

前もって感謝します。

4

2 に答える 2

13

まず、使用しないでくださいinsert_at。パフォーマンスが低下する理由ではありませんが、不要で見栄えが悪くなります。設定するだけですnode.parent

for new_record in new_records:
    new_node = MyMPTTModel(..., parent=get_parent(new_record))
    new_node.save()

次に、パフォーマンスの質問です。最新の mptt (git master、0.5.4 ではありません) を使用している場合は、delay_mptt_updatesすべてのノードを追加するまで、mptt がこれらの多くの更新を実行するのを防ぐために呼び出されるコンテキスト マネージャーがあります。

with transaction.atomic():
    with MyMPTTModel.objects.delay_mptt_updates():
        for new_record in new_records:
            new_node = MyMPTTModel(..., parent=get_parent(new_record))
            new_node.save()

または、ツリー全体に触れている場合はdisable_mptt_updates、最後にツリー全体を使用して再構築することで、さらに高速化できます。

with transaction.atomic():
    with MyMPTTModel.objects.disable_mptt_updates():
        for new_record in new_records:
            new_node = MyMPTTModel(..., parent=get_parent(new_record))
            new_node.save()
    MyMPTTModel.objects.rebuild()
于 2012-10-01T21:05:12.407 に答える
1

Django-MPTT はツリー構造を維持します。そのため、それぞれinsert_atで、挿入されたノードの右側にあるすべてのノードが変更されます。これが、パフォーマンスの問題が発生している理由です。

1 つの方法は、 を使用せずにツリー構造を手動で構築することdjango-mpttです。

したがって、新しいレコードを取得する必要があり、それらに従って、ツリー内の古いノードを変更する必要があるかどうかを判断します。データを挿入するだけなので、左右の属性のみが変更されますが、レベルは変更されないため、少し簡単になるはずです。変更するノードがわかったら、1 つのupdateトランザクション ( edit ) を使用してそれらを変更できます。

その後、新しいデータの挿入を開始できます。繰り返しますが、最速の方法は、新しいエントリごとに左、右、およびレベルの値を計算してから実行することですbulk_insert(Django>=1.4)。これを行うと、db トランザクションに関して明らかにはるかに高速になる 2 つの db 操作のみが発生します。

ただし、この方法では、ツリー内の古いノードを変更する方法を理解するためのスマートな方法が必要になります。最も簡単な方法は、すべてのツリーを Python 構造にダンプし、その構造の変更を把握することです。ただし、メモリの制限によりツリーが非常に大きい場合、これは実現できません。

今のところ、これを行うより効率的な方法があるかどうかはわかりません。たぶん、StackOverflow の他の誰かがいくつかのクールなアイデアを持っています...

編集

update混乱して申し訳ありません。私は1つのトランザクションを意味しました。このような場合、私は通常、生の SQL クエリを実行しupdate tbname set ... where id=1; update tbname set ... where id=2;ます。そのため、1 つの SQL クエリで複数の SQL ステートメントを実行します。私の経験から、db の高価な部分はステートメントの実行ではなく、ネットワーク遅延、db ロックなどがあるため、トランザクション自体です。ただし、クエリセットを使用してdjangoでそれを行う方法がわかりません。私は通常、生のSQLクエリを実行します。

于 2012-09-30T14:55:05.217 に答える