TIL #40 select_related & prefetch_related


queryを実行してデータベース内のデータを取得し、select relatedとprefetch relatedを使用して最小queryで最大のパフォーマンスを取得します(データベースへのアクセスを低減し、処理速度を向上させます).
この2つの方法の共通点は、初期queryによって関連データをキャッシュに格納し、必要なデータをデータベースから書き込むことですが、queryを実行する方法と用途にはいくつかの違いがあります.

1. select_related

  • 正参照関係では
  • を用いる.
  • JOINを使用してクエリー
  • を実行する.
  • select関連使用前
    -コード
    -query =>SELECT queryは引き続き実行されます.
  • select関連使用後
    -コード=>参照関係「series」と「color filtert color」のデータを一緒にインポートします.
    -query =>SELECT queryを1回行った後、クエリは行われません.
  • 2. prefetch_related

  • 逆参照、多対多、多対一関係で使用します.
  • select relatedとは異なり、JOIN以外の逆参照関係で2つの個別のクエリーを実行した後、Pythonに追加します.
  • プリフェッチ関連例
    =>カテゴリの逆参照に関連する飲料がプリフェッチ関連として使用される場合、categoryおよび飲料の様々な態様のクエリが見られる.
    =>prefetch relatedクエリの後、キャッシュに格納されたデータを使用してクエリを実行せずにデータをインポートできます.
  • 3.注意事項


    Note
    Remember that, as always with QuerySets, any subsequent chained methods which imply a different database query will ignore previously cached results, and retrieve data using a fresh database query. So, if you write the following:
    >pizzas = Pizza.objects.prefetch_related('toppings')
    >[list(pizza.toppings.filter(spicy=True)) for pizza in pizzas]
    …then the fact that pizza.toppings.all() has been prefetched will not help you. The prefetch_related('toppings') implied pizza.toppings.all(), but pizza.toppings.filter() is a new and different query. The prefetched cache can’t help here; in fact it hurts performance, since you have done a database query that you haven’t used. So use this feature with caution!
    ソース:https://docs.djangoproject.com/en/3.0/ref/models/querysets/#django.db.models.query.QuerySet.select_related
    要約:プリフェッチrelatedを使用してtoppingを呼び出しても.filterは異なるクエリーを実行するため、プリフェッチを使用すると効率的ではない可能性があります.