2017-05-01 5 views
2

Djangoアプリケーションをテストする際に、特定のフィルタ()が使用されたときに特定のクエリでパフォーマンスの問題が発生しました。問題は解決しましたが、私は理由を理解していません。Django filter()は減らすのではなく結果のQuerySetを増加させます

私は3つの基準に基づいてクエリセットをフィルタリングしています。一度にすべてを含めると、期待される結果が得られます。いずれかの句を独自のfilter()呼び出しに移動すると、結果として得られるQuerySetは、はるかに大きく、一見重複した項目で埋められます。

この説明は以下を参照してください。 result__is_false=False句を独自のfilter()に移動すると、結果のQuerySetが大幅に拡張されます。

>>> Finding.objects.filter(project=1, result__scan_session__is_enabled=True,\ 
    result__is_false=False).count() 
3566 

>>> Finding.objects.filter(project=1, result__scan_session__is_enabled=True)\ 
    .filter(result__is_false=False).count() 
10050380 

問題は、条件付きで問題になっているフィルタを適用する必要があり、毎回ではありませんでした。トリックを行っているように見えた

>>> Finding.objects.filter(project=1, result__scan_session__is_enabled=True)\ 
    .exclude(result__is_false=True).count() 
3566 

:私はこのような除外()ルーチンにフィルタ()ルーチンを変換することによって、問題を解決しました! 、

1)フィルタ()およびexclude()を説明する記事は、彼らが反対で大きさが等しいとして扱うことができることを示唆しているように見える理由:私はこれが働いたことを幸せに思いますが

は、私は2つのことを理解していません上記の例に基づいて、必ずしもそうとは限りません。

2)なぜresult__is_false=False句を独自のフィルタ()に移動すると、最初の結果で大きなジャンプが発生しました。

誰にもこれらのいずれかの洞察がありますか?

+2

'print(Finding.objects.filter(...)。query)'でクエリを出力し、すべてが返信されます – wim

+0

2番目の部分(問題の内容を説明する)は、おそらく回答として投稿する必要があります。 – EJoshuaS

答えて

2

これらの両方は、連続するfilterの呼び出しが多値関係でどのように機能するかの予測結果のように見えます。 docsは、実施例で詳細に説明:単一フィルタ()コール内部

すべては、すべてのこれらの要件に合致するアイテムを除外 に同時に印加されます。連続するfilter() コールはさらにオブジェクトセットを制限しますが、複数値の リレーションの場合、それは以前のfilter() 呼び出しによって選択されたオブジェクトではなく、 ではなく、プライマリモデルにリンクされたオブジェクトに適用されます。

したがって、2番目のfilterコールでは、少なくとも1つの非偽の結果があるFindingが返されます。 exclude呼び出しは、少なくとも1つの偽の結果がない場合にはすべての結果を返します。単一の値でnullableではないフィールドを照会する際には互換性がありますが、すべての場合ではありません。

+0

ありがとうピーター!私はそのページをしばらく前に読んでいましたが、あなたがそれを指摘するまで、それは私の状況に適用可能であったことを実際にはクリックしませんでした。今度は私のコードに戻り、後続のfilter()呼び出しを再評価し、おそらくexclude()に変更します。 – rjd

関連する問題