2012-01-12 8 views
7

मेरे पास Django में एक जटिल डेटाबेस मॉडल स्थापित है, और मुझे फ़िल्टर डेटा के आधार पर कई गणनाएं करनी हैं। मेरे पास Test ऑब्जेक्ट है, एक TestAttempt ऑब्जेक्ट, और UserProfile ऑब्जेक्ट (परीक्षण के लिए एक विदेशी कुंजी के साथ और उपयोगकर्ता प्रोफ़ाइल के लिए एक विदेशी कुंजी)। एक ऐसी विधि है जिसे मैं TestAttempt पर चलाता हूं जो परीक्षण स्कोर की गणना करता है (प्रत्येक परीक्षण से जुड़े सही उत्तरों की तुलना में कई उपयोगकर्ता द्वारा प्रदान किए गए विकल्पों के आधार पर)। और फिर एक और तरीका जो मैं Test पर चलाता हूं जो उसके प्रत्येक TestAttempt के आधार पर औसत परीक्षण स्कोर की गणना करता है लेकिन कभी-कभी मैं केवल TestAttempt के एक आपूर्ति किए गए सबसेट के आधार पर औसत चाहता हूं जो किसी विशेष सेट से जुड़े होते हैं UserProfiles का। तो किसी विशेष परीक्षण के लिए औसत परीक्षण स्कोर की गणना करने के बजाय:क्वेरीसेट्स के लिए django __in लुकअप की दक्षता

[x.score() for x in self.test_attempts.all()] 

और फिर इन मानों का औसत। मैं इस तरह एक प्रश्न कार्य करें:

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

जहां user_id_list UserProfile पहचान-पत्र है जिसके लिए मैं एक सूची के रूप में औसत परीक्षण स्कोर लगाना चाहते हैं का कोई खास सबसेट है। मेरा सवाल यह है: यदि user_id_list वास्तव में UserProfile का पूरा सेट है (इसलिए फ़िल्टर self.test_attempts.all() जैसा ही वापस आ जाएगा) और अधिकांश समय यह मामला होगा, क्या यह इस मामले की जांच करने के लिए भुगतान करता है, और यदि ऐसा है बिल्कुल फ़िल्टर निष्पादित नहीं करते? या __in लुकअप इतना कुशल है कि user_id_list में सभी उपयोगकर्ता शामिल हैं, यह फ़िल्टर चलाने के लिए अधिक कुशल होगा। साथ ही, क्या मुझे परिणामी test_attempts को अलग() बनाने के बारे में चिंता करने की ज़रूरत है? या वे मेरी क्वेरीसेट की संरचना के साथ डुप्लिकेट को चालू नहीं कर सकते हैं?

संपादित करें:

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 

और इस फिल्टर के साथ:

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)) 

ध्यान दें कि सरणी किसी को जो कच्चे SQL क्वेरी को देख में रुचि है के लिए, यह इस तरह फिल्टर के बिना लग रहा है (1,2,3) सिर्फ एक उदाहरण है

+0

दोनों मामलों में एसक्यूएल जेनरेट किया गया है? –

+0

सुनिश्चित नहीं है, मैं किसी विशेष क्वेरी सेट के लिए SQL को आउटपुट कैसे करूं? संपादित करें, इसे समझ लिया। इसे खोजने के लिए मुझे एक पल दें – ecbtln

+0

एसक्यूएल प्रश्न जोड़े गए हैं – ecbtln

उत्तर

2
  1. संक्षिप्त उत्तर है - बेंचमार्क। इसे विभिन्न स्थितियों में परीक्षण करें और लोड को मापें। यह सबसे अच्छा जवाब होगा।

  2. यहां डुप्लीकेट नहीं हो सकते हैं।

  3. क्या यह वास्तव में दो बैठकों की जांच करने में एक समस्या है? यहाँ 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 स्तर पर औसत की गणना नहीं कर सकते? यह आपको अधिक उल्लेखनीय perfomance बढ़ावा देगा।

  5. और कैशिंग के बारे में मत भूलना।

2

जो मैं दस्तावेज के बारे में समझता हूं, उससे सभी प्रश्न वास्तव में उपयोग किए जाने से पहले बनाए जाते हैं। इसलिए, उदाहरण के लिए, test_attempts.all() एक बार SQL कोड उत्पन्न करता है और जब आप क्वेरी निष्पादित करते हैं, तो वास्तव में .count(), for t in test_attempts.all(): इत्यादि जैसे कुछ करके डेटा प्राप्त करें, यह डेटाबेस पर क्वेरी चलाता है और एक क्वेरीसेट ऑब्जेक्ट देता है या केवल एक ऑब्जेक्ट देता है प्राप्त()। इसे ध्यान में रखते हुए, डेटाबेस में कॉल की संख्या बिल्कुल वही होगी, जबकि वास्तविक कॉल अलग होगा। जैसा कि आप अपनी संपादित पोस्ट में दिखाते हैं, कच्चे प्रश्न अलग-अलग होते हैं, लेकिन डीजेगो द्वारा डेटा तक पहुंचने से पहले, वे दोनों एक ही तरीके से उत्पन्न होते हैं। एक Django परिप्रेक्ष्य से, वे दोनों एक ही फैशन में बनाया जाएगा, और फिर डेटाबेस पर निष्पादित किया जाएगा। मेरी राय में, यह सभी() स्थिति के लिए परीक्षण नहीं करना सबसे अच्छा होगा, क्योंकि आपको इसे निर्धारित करने के लिए दो प्रश्नों को चलाने होंगे। मेरा मानना ​​है कि आपको अपने पास कोड के साथ चलना चाहिए और सभी() परिदृश्य के लिए जांच छोड़ना चाहिए, जिसे आप सबसे आम मामले के रूप में वर्णित करते हैं। अधिकांश आधुनिक डेटाबेस इंजन इस तरह से प्रश्नों को चलाते हैं कि जोड़े गए जोड़े प्रदर्शन मीट्रिक में बाधा नहीं डालते हैं, क्योंकि वे इष्टतम अनुक्रमों में क्वेरी को संसाधित करते हैं, वैसे भी।

2

उपयोग Annotation बजाय क्वेरीसमूहों, जो user_id_list में हर आइटम के लिए एक नया डेटाबेस हिट बनाने और अजगर में औसत प्रदर्शन कर रहा है से अधिक पाशन।

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

क्वेरी सेट में ऑब्जेक्ट्स पर एक विशेषता के रूप में उपलब्ध औसत के साथ क्वेरी सेट वापस कर देगा। ओआरएम का उपयोग करने के लिए आपको अपने विदेशी-महत्वपूर्ण संबंधों में संरचनात्मक परिवर्तन करने की आवश्यकता हो सकती है और एनोटेशन को सुविधाजनक बनाने के लिए कौन सा मॉडल रखता है। यदि आवश्यक हो, तो यह पुनरावर्तक लाभकारी साइड इफेक्ट्स (डेटा कुछ तरीकों से जीना पसंद करता है) तो यह एक अच्छा अभ्यास है।

संबंधित मुद्दे