Django ORMクエリーの最適化
状元は特定の時期にのみクエリーされます.
その時期を知ってこそ最適化できる.
Django ORM機能 Lazy Loading
-ディレイコール
Eager Loading
-即時ロード:N+1 Problem
ORMの特徴は、本当に必要なときだけSQLを呼び出すことです.
言い換えれば、本当に必要な時でなければ
QuerySetはSQLを呼び出さない
Djangoがクエリを発行した時刻
正解は2回
最初のプレイヤーとすべてのプレイヤーをインポートするには、User.objects.すべての命令を持ってきたと思います.
先ほど述べたように、この文章はSQL文を呼び出していません.
つまり、まだデータを持ってきていません.
したがって、最初のユーザをインポートするためにusers[0]と呼びます.
一度、SQL文が呼び出されたためです.
およびすべてのユーザ情報を取得するためのlist(users).
つまり、SQL文を再度呼び出し、2回のクエリが発生します.
N+1問題
ゲートを回転するたびにクエリごとにsqlが呼び出される問題をN+1問題と呼ぶ.
(ユーザを一度に呼び出すsql)+(ユーザ数N)=(N+1クエリ)
この問題を解決する美しい方法を紹介したいです.
select_related, prefetch_related, Prefetch
1. select_relatedオブジェクトは、1対1または複数対1の逆参照とすることができる.
または外部キーを参照する場合の SQL INNER JOINにて直ちに をロード
これにより、パフォーマンスが向上します.
上図にselect relatedなしでデータをインポートする例を示します.
類似または重複したクエリーが重複し続けることがわかります.
ただし、select relatedを使用すると、最小限のクエリーでデータをロードできることがわかります.
2. prefetch_relatedオブジェクトがM:N関係、または逆参照の場合は を使用します. Python追加クエリー
prefet relatedを使用するとselect relatedと似ています.
冗長クエリーを削減し、パフォーマンスを向上させます.
3. Prefetch他のクエリセットを制御する方法
私たちは常に追加のクエリーセットを制御したいと思っています.
この場合、prefetch relatedでprefetchを使用することができます.
その時期を知ってこそ最適化できる.
Django ORM機能
-ディレイコール
-即時ロード:N+1 Problem
言い換えれば、本当に必要な時でなければ
QuerySetはSQLを呼び出さない
Djangoがクエリを発行した時刻
user = User.objects.all()
a = user.filter(first_name='a') # 아직 DB에서 데이터를 가져오지않음
order_a = a.order_by('id') # 아직 DB에서 데이터를 가져오지않음
b = user.get(id=1)
parent = b.parent.name # << 여기서 쿼리를 날림
では、次の文では、何回クエリーを実行するかを当ててみましょう.users = User.objects.all()
first_user = users[0]
user_list = list(users)
正解は2回
最初のプレイヤーとすべてのプレイヤーをインポートするには、User.objects.すべての命令を持ってきたと思います.
先ほど述べたように、この文章はSQL文を呼び出していません.
つまり、まだデータを持ってきていません.
したがって、最初のユーザをインポートするためにusers[0]と呼びます.
一度、SQL文が呼び出されたためです.
およびすべてのユーザ情報を取得するためのlist(users).
つまり、SQL文を再度呼び出し、2回のクエリが発生します.
ゲートを回転するたびにクエリごとにsqlが呼び出される問題をN+1問題と呼ぶ.
(ユーザを一度に呼び出すsql)+(ユーザ数N)=(N+1クエリ)
この問題を解決する美しい方法を紹介したいです.
select_related, prefetch_related, Prefetch
1. select_related
または外部キーを参照する場合の
class Child(models.Model):
name = models.CharField(max_length=20)
def __str__(self):
return self.name
class Parent(models.Model):
children = models.ForeignKey("Child", related_name="parent", on_delete=models.CASCADE)
name = models.CharField(max_length=100)
def __str__(self):
return self.name
以上のモデルは,1:Nからなる関係型モデルである.qs = Parent.objects.select_related("children")
上記のクエリを使用して、最小数(重複クエリを減らす)でデータを取得します.これにより、パフォーマンスが向上します.
上図にselect relatedなしでデータをインポートする例を示します.
類似または重複したクエリーが重複し続けることがわかります.
ただし、select relatedを使用すると、最小限のクエリーでデータをロードできることがわかります.
2. prefetch_related
qs = children.objects.prefetch_related("parent")
逆参照として、Childの立場で使う様子.prefet relatedを使用するとselect relatedと似ています.
冗長クエリーを削減し、パフォーマンスを向上させます.
3. Prefetch
Prefetch(lookup, queryset=None, to_attr=None)
Prefetchの原型.私たちは常に追加のクエリーセットを制御したいと思っています.
この場合、prefetch relatedでprefetchを使用することができます.
from django.db.models import Prefetch
queryset = post_models.Parent.objects.prefetch_related(
Prefetch(
"child",
queryset=post_models.Child.objects.prefetch_related(
Prefetch(
"child_of_child",
queryset=post_models.ChildofChild.objects.prefetch_related("
"child_of_child_of_child"
")
)
)
))
上記のようにデータテープ間の深さ接続形態を制御してもよい.Reference
この問題について(Django ORMクエリーの最適化), 我々は、より多くの情報をここで見つけました https://velog.io/@masterkorea01/Django-ORM-쿼리-최적화テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol