2012-01-12 14 views
7

私は複雑なデータベースモデルをDjangoに設定しており、フィルタデータに基づいていくつかの計算を行う必要があります。私は、Testオブジェクト、TestAttemptオブジェクト、およびUserProfileオブジェクト(テストするための外部キーと、userprofileへの外部キー)を持っています。テストスコアを計算するTestAttemptで実行する方法があります(各テストに関連する正しい回答と比較して、ユーザーが提供する選択肢の数に基づいています)。そして、私がTestで実行している別の方法は、それぞれの関連するTestAttemptに基づいて平均テストのスコアを計算しますが、時には特定のセットにリンクされているTestAttemptの付属サブセットUserProfilesです。したがって、特定のテストの平均テストスコアをこのように計算する代わりに、これらの値を平均化して平均化することができます。 user_id_listは、私は、リストの形式で平均テストスコアを見つけるしたいのUserProfileのIDの特定のサブセットであるdjangoの効率性クエリーセットの検索

[x.score() for x in self.test_attempts.filter(profile__id__in=user_id_list).all()] 

: 私はこのようなクエリを実行します。私の質問はこれです:もしuser_id_listが本当にUserProfileのセット全体であるなら(フィルタはself.test_attempts.all()と同じになります)、ほとんどの場合、この場合に当てはまります。フィルタをまったく実行しないでください。または__inルックアップで十分に効率的です。user_id_listにすべてのユーザーが含まれていても、フィルタを実行する方が効率的です。また、結果として得られるtest_attemptsをdistinct()にすることについて心配する必要はありますか?彼らは私のクエリーセットの構造で重複を立てることはできませんか?

EDIT:配列こと

SELECT "mc_grades_testattempt"."id", "mc_grades_testattempt"."date", 
"mc_grades_testattempt"."test_id", "mc_grades_testattempt"."student_id" FROM 
"mc_grades_testattempt" INNER JOIN "mc_grades_userprofile" ON 
("mc_grades_testattempt"."student_id" = "mc_grades_userprofile"."id") WHERE 
("mc_grades_testattempt"."test_id" = 1 AND "mc_grades_userprofile"."user_id" IN (1, 2, 3)) 

注:フィルター付き

SELECT "mc_grades_testattempt"."id", "mc_grades_testattempt"."date", 
"mc_grades_testattempt"."test_id", "mc_grades_testattempt"."student_id" FROM 
"mc_grades_testattempt" WHERE "mc_grades_testattempt"."test_id" = 1 

と、この:生のSQLクエリを見に興味があります誰のためには、フィルタなし、このようになります。 (1,2,3)は単なる例です

+0

両方の場合に生成されるSQLは何ですか? –

+0

わからない、特定のクエリセットのSQLを出力するにはどうすればよいですか?編集、それを考え出した。私にそれを見つけるための瞬間を与えてください – ecbtln

+0

SQLクエリが追加されました – ecbtln

答えて

2
  1. 短い回答は - ベンチマークです。さまざまな状況でそれをテストし、負荷を測定します。それは最高の答えになります。

  2. ここで重複することはできません。

  3. 2つのサポーションを確認することは本当に問題ですか?ここでhypoteticコードです:

    def average_score(self, user_id_list=None): 
        qset = self.test_attempts.all() 
        if user_id_list is not None: 
         qset = qset.filter(profile__id__in=user_id_list) 
        scores = [x.score() for x in qset] 
        # and compute the average 
    
  4. は私がscoreメソッドが何をするのか知りませんが、あなたは、DBのレベルでの平均値を計算することができませんか?それはあなたにもっと顕著な性能向上を与えるでしょう。

  5. キャッシングについて忘れないでください。

2

私がドキュメントを理解しているので、すべてのクエリは実際に使用される前に構築されています。したがって、たとえばtest_attempts.all()はSQLコードを1回生成します。クエリを実行すると、.count(),for t in test_attempts.all():などのデータを実際に取得すると、データベースでクエリが実行され、Querysetオブジェクトが返されます。取得する()。そのことを念頭において、データベースへの呼び出しの数はまったく同じですが、実際の呼び出しは異なります。編集した投稿に表示すると、生のクエリは異なりますが、データはDjangoがアクセスする前に同じ方法で生成されます。 Djangoの観点からは、両方とも同じ方法で作成され、データベース上で実行されます。私の意見では、それを決定するために2つのクエリを実行しなければならないので、all()状況をテストしない方がよいでしょう。私はあなたが持っているコードを実行し、最も一般的なケースとして記述するall()シナリオのチェックをスキップする必要があると思います。最近のデータベースエンジンでは、クエリを最適な順序で処理するため、追加された結合がパフォーマンスメトリックを妨げないようにクエリを実行します。

2

利用Annotation代わりのuser_id_list内のすべての項目のための新しいデータベースヒットを作成し、Pythonで平均を実行しているクエリセット、をループします。

ms = MyModel.objects.annotate(Avg('some_field')) 
ms[0].avg__some_field # prints the average for that instance 

クエリセット内のオブジェクトの属性として利用可能な平均を持つクエリセットを返します。 ORMを使用すると、外部キー関係を構造的に変更する必要があり、アノテーションを便利にするためにどのモデルがどのデータを保持するかが必要になる場合があります。この並べ替えは、必要に応じて有益な副作用(データが特定の方法で生きていくことが好き)をもたらすので、良い演習です。

関連する問題