多くの調査の結果、問題は管理者検索フィールド(ChangeList
内)の検索クエリがどのように構築されているかに起因することがわかりました。 クラス)。複数用語検索(スペースで区切られた単語)では、新しいfilter()
をチェーンすることにより、各用語がQuerySetに追加されます。 。 search_fields
に1つ以上の関連フィールドがある場合 、作成されたSQLクエリには多くのJOIN
が含まれます 多くのJOIN
で次々にチェーンされています 関連するフィールドごとに(私の関連する質問
いくつかの例と詳細について)。このJOIN
のチェーン 各用語が先行用語によるデータフィルターのサブセットでのみ検索されるように、そして最も重要なのは、関連フィールドが一致するために1つの用語のみ(すべての用語が必要)である必要があるということです。 複数値の関係のスパン このテーマの詳細については、Djangoドキュメントをご覧ください。管理者検索フィールドでほとんどの場合必要な動作であると確信しています。
このクエリ(関連するフィールドが含まれる)の欠点は、パフォーマンス(クエリを実行する時間)の変動が非常に大きくなる可能性があることです。検索された用語の数、検索された用語、フィールド検索の種類(VARCHARなど)、フィールド検索の数、テーブル内のデータ、テーブルのサイズなど、多くの要因によって異なります。適切な組み合わせを使用すると簡単です。ほとんど永遠にかかるクエリを作成する(私にとって10分以上かかるクエリは、この検索フィールドのコンテキストで永遠にかかるクエリです)。
非常に時間がかかる場合がある理由は、データベースが用語ごとに一時テーブルを作成し、それをほぼ完全にスキャンして次の用語を検索する必要があるためです。ですから、これは非常に迅速に加算されます。
パフォーマンスを改善するために行うことができる変更は、 ANDedです。 同じfilter()
内のすべての用語 。このようにして、それらは1つのJOIN
になります 多くではなく、関連するフィールド(または多対多の場合は2)によって。このクエリははるかに高速で、パフォーマンスの変動は非常に小さくなります。欠点は、関連するフィールドに一致するすべての用語が必要になるため、多くの場合、一致するものが少なくなる可能性があることです。
更新
trinchetからの質問 検索動作を変更するために必要なものは次のとおりです(Django 1.7の場合)。 get_search_results()
をオーバーライドする必要があります この種の検索が必要な管理クラスの基本クラス(ModelAdmin
)からすべてのメソッドコードをコピーする必要があります )あなた自身のクラスに。次に、これらの行を変更する必要があります:
for bit in search_term.split():
or_queries = [models.Q(**{orm_lookup: bit})
for orm_lookup in orm_lookups]
queryset = queryset.filter(reduce(operator.or_, or_queries))
それに:
and_queries = []
for bit in search_term.split():
or_queries = [models.Q(**{orm_lookup: bit})
for orm_lookup in orm_lookups]
and_queries.append(Q(reduce(operator.or_, or_queries)))
queryset = queryset.filter(reduce(operator.and_, and_queries))
このコードはテストされていません。私の元のコードはDjango1.4用でしたが、ここでは1.7に適合させています。