2017-12-23 24 views
1

私は(バッチMLの目的で)+ 500万人以上のアイテムのクエリセットを扱っていると私はに必要なクエリセットを評価せずにクエリセット(私は、マルチスレッド操作を行うことができます)を分割しましたクエリーセット内の各項目に一度アクセスするため、原因を評価するクエリーセット項目をキャッシュしたくありません。Djangoクエリーセットを評価せずに分割する方法はありますか?私は今までに必要と

項目を1つのクエリーセットに選択し、評価なしで分割することはできますか?あるいは、私はLimits [:size]を使って複数のクエリーセットをクエリすることでこの問題を解決する必要がありますか?

NB:私は反復処理可能で、それを評価せずにクエリセットを循環するために使用することができますが、私の質問は(可能であれば)私は、その後の各上のiterableを実行するために、クエリセットを分割することができますどのように関連していることを認識しています分割されたクエリーセット。

+1

それを繰り返して、ワーカースレッドが作業をフェッチできるようにしてください。これは、Djangoを使った単一のクエリで動作することが想像できる唯一の方法です。 (ちょうどかなり多くのスレッドセーフ反復子を渡します。) – Ryan

+1

djangoクエリは、何か強制的な評価に達するまで評価されません。そしてスライスすることができます。だからmyQuery [1000:11000]はきれいにあなたにクエリの一部を与えます。そして、いいえ、スライスを得るために全体を評価するわけではありません。 –

答えて

4

Djangoはあなたがページ分割データを管理するのに役立ついくつかのクラスを提供 - それはあるが、データ数ページにわたって分割されます、 「次へ/前へ」リンクを:

from django.core.paginator import Paginator 

object_list = MyModel.objects.all() 
paginator = Paginator(object_list, 10) # Show 10 objects per page, you can choose any other value 

for i in paginator.page_range(): # A 1-based range iterator of page numbers, e.g. yielding [1, 2, 3, 4]. 
    data = iter(paginator.get_page(i)) 
    # use data 
+1

私は私の問題のために、ページャーが最高の解決策のように思えると思っています。 N.B.:ページのアイテムを読む人は、要求があるまで評価されません。つまり、遅延評価 – bmjrowe

1

することができますはい、更新答えパーこのgist

からのように:

def queryset_iterator(queryset, chunk_size=1000): 
""" 
Iterate over a Django Queryset ordered by the primary key 
This method loads a maximum of chunk_size (default: 1000) rows in it's 
memory at the same time while django normally would load all rows in it's 
memory. Using the iterator() method only causes it to not preload all the 
classes. 
Note that the implementation of the iterator does not support ordered query sets. 
""" 
    try: 
     last_pk = queryset.order_by('-pk')[:1].get().pk 
    except ObjectDoesNotExist: 
     return 

    pk = 0 
    queryset = queryset.order_by('pk') 
    while pk < last_pk: 
     for row in queryset.filter(pk__gt=pk)[:chunk_size]: 
      pk = row.pk 
      yield row 
     gc.collect() 
1

スレッドにクエリセットを渡します私がお勧めするものではありません。私はあなたがやろうとしていることを知っていますが、その理由は分かりますが、各スレッドに何らかのパラメータセットを渡して、スレッドが部分的なクエリを実行するようにしてください。 このようにして、スレッドは呼び出しコードとは区別されます。

DBのクエリが多いために発生する遅延を回避するためにスレッドを使用しようとしている場合、トランザクション管理を使用する方がよいでしょう。 このリンクlinkには便利なヒントがいくつかあります。私はスレッドの代わりにこれを使用します

関連する問題