Django ORM は、Django の最も強力な機能の 1 つです。これにより、データベースとのやり取りの複雑さの多くが抽象化され、開発者は生の SQL ではなく Python 構文を使用してデータを操作できるようになります。これらすべての ORM 関数は、慎重に処理しないとボトルネックになる可能性がある SQL クエリを生成します。
このブログでは、Django ORM を使用する際のよくある間違いを強調し、クエリの効率性、保守性、パフォーマンスを維持するためのヒントも提供します。
N 1 クエリの問題は、コードが 1 つのクエリをトリガーして一連のレコードを取得し、その後 N 個の追加のクエリを再度実行して関連データを取得するときに発生します。
blogs = Blog.objects.all() # 1 Query for blog in blogs: print(blog.author.name) # N additional queries
上記の例では、ループ内で blog.author.name にアクセスすると、Django が各ブログの著者レコードを個別にフェッチし、N 個の追加クエリが発生します。
修正方法
SQL JOIN を実行してメイン オブジェクトとその関連オブジェクトを 1 つのクエリで取得するため、単一の関連オブジェクト (ForeignKey や OneToOneField など) には select_popular を使用します。多対多、多対 1、または逆の関係の場合は、prefetch_relative を使用します。これにより、関連するデータが個別のクエリでフェッチされますが、それらのデータが Python で効率的に結合され、N 1 の問題が回避されます。
# With select_related blogs = Blog.objects.select_related('author').all() # With prefetch_related authors = Author.objects.prefetch_related('blogs').all()
開発者は、複数のフィルターをチェーンしたり、.all() を使用した後に同じクエリセットに対してクエリを繰り返したりすることがよくあります。
blogs = Blog.objects.all() active_blogs = blogs.filter(is_archived=False) popular_blogs = blogs.filter(views__gte=1000)
Django は必要な場合にのみクエリセットを遅延評価してクエリセットを最適化しようとしますが、同じクエリセット データに対してフィルターを繰り返し呼び出すと、データベースに不要なヒットが発生する可能性があります。
修正方法
フィルターを 1 つのステートメントに結合すると、django は単一の SQL クエリを生成できます。
popular_active_blogs = Blog.objects.filter(is_archived=False, views__gte=1000)
モデルのすべてのフィールド データではなく、特定のフィールドのみが必要な場合があります。この間、.values() または .values_list() を使用すると、より効率的になります。
titles = Blog.objects.values('title') or titles = Blog.objects.values_list('title', flat=True) # values() returns a list of dictionaries. # values_list() can return tuples or flat values if flat=True is provided.
必要な列のみをフェッチすることで、データベースから転送されるデータ量が削減され、パフォーマンスが向上します。
.aggregate() または .annotate() を繰り返し呼び出すと、複数のクエリが発生する可能性があります。複数の注釈を含む複雑なクエリは非効率的な SQL クエリにつながる可能性があり、データベース操作が重くなる可能性があります。
# Example of multiple aggregate total_count = Blog.objects.aggregate(Count('id')) author_count = Blog.objects.aggregate(Count('author')) average_views = Blog.objects.aggregate(Avg('views'))
おすすめ
blogs = Blog.objects.all() # 1 Query for blog in blogs: print(blog.author.name) # N additional queries
インデックスを作成すると、データベースがデータを迅速に検索して取得できるようになり、低速の全テーブル スキャンが回避され、クエリのパフォーマンスが向上します。インデックスにより、フィルタリング、並べ替え、結合などの操作が最適化され、頻繁にアクセスされるフィールドに対するクエリが大幅に高速化されます。頻繁にクエリされるフィールドのデータベース インデックスが欠落していると、パフォーマンスが大幅に低下する可能性があります。
Django でインデックスを追加する方法
# With select_related blogs = Blog.objects.select_related('author').all() # With prefetch_related authors = Author.objects.prefetch_related('blogs').all()
インデックスを使用すると読み取り速度は速くなりますが、書き込み速度は遅くなります。したがって、頻繁にクエリを実行する必要があるフィールドのみにインデックスを付けてください。
計算にコストがかかるデータ、またはめったに変更されないデータをクエリする必要がある場合は、キャッシュを使用します。 5 分間でもキャッシュすると、繰り返されるクエリ、複雑な計算、および頻繁に変更されないクエリを保存できます。
blogs = Blog.objects.all() active_blogs = blogs.filter(is_archived=False) popular_blogs = blogs.filter(views__gte=1000)
Django ORM は、複雑なクエリや一括操作を効率的に表現できない場合があります。 Django は .extra() または .raw() を提供しますが、次の理由から生の SQL の使用は最後の手段である必要があります。
入力が適切にサニタイズされ、生の SQL クエリが保守可能に保たれるようにします。
これらのヒントを適用すると、コードをクリーンで保守しやすく保ちながら、Django アプリのパフォーマンスが向上します。また、開発環境で Django Debug Toolbar を使用して、実行されるクエリの数、実行時間、SQL ステートメントを監視および分析することも提案されています。
以上が修正すべき Django ORM の一般的な間違いの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。