7

मैं अपने प्रोजेक्ट के डीबी कॉल के अनुकूलन पर काम कर रहा है और मैं नीचे दो समान कॉल के बीच प्रदर्शन में एक "महत्वपूर्ण" अंतर पर ध्यान:ActiveRecord क्वेरी सीधे एसक्यूएल से धीमी है?

connection = ActiveRecord::Base.connection() 
pgresult = connection.execute(
    "SELECT SUM(my_column) 
    FROM table 
    WHERE id = #{id} 
    AND created_at BETWEEN '#{lower}' and '#{upper}'") 

और दूसरे संस्करण:

sum = Table. 
     where(:id => id, :created_at => lower..upper). 
     sum(:my_column) 

औसतन पहले संस्करण का उपयोग करने के तरीके को 300 एमएमएस निष्पादित करने के लिए लगता है (ऑपरेशन को इसके भीतर कुल दो हजार बार कहा जाता है), और दूसरे संस्करण का उपयोग करने वाली विधि लगभग 550ms लेती है। यह गति में लगभग 100% की कमी है।

मैंने दूसरे संस्करण द्वारा जेनरेट किए गए एसक्यूएल को दोबारा जांच लिया है, यह टेबल नाम के साथ तालिका तालिका को पूर्ववत करने के लिए अपवाद के साथ पहले जैसा है।

  • धीमी गति क्यों? क्या ActiveRecord और SQL वास्तव में ऑपरेशन करने के बीच रूपांतरण लगभग 2x लेता है?
  • अगर मुझे एक ही ऑपरेशन करने की ज़रूरत है तो मुझे सीधे एसक्यूएल (शायद यहां तक ​​कि एक स्पोक) लिखने के लिए चिपकने की ज़रूरत है और मैं ओवरहेड को हिट नहीं करना चाहता हूं?

धन्यवाद!

+1

सिर्फ .explain का उपयोग करें और क्वेरी उत्पन्न हुए उस को देखो, मैं वे दोनों समान, लागत रहे हैं यकीन है कि यह अलग दिखता है और thats क्यों यह इतना अब – antpaw

+0

लेता है मैं दोबारा जांच क्वेरी योजनाओं हूँ, और सब। प्रतिस्थापित करना था। दूसरे संस्करण में .sum से चयन करें, क्योंकि आप उस से एक फिक्सम वापस प्राप्त करते हैं और मुझे उत्पन्न करने के लिए उपयोग की जाने वाली क्वेरी पर एक एक्सप्लैन करने का कोई तरीका नहीं मिल रहा है। –

उत्तर

2

कुछ चीजें बाहर निकलती हैं।

सबसे पहले, अगर इस कोड को 2000 बार कहा जा रहा है और चलाने के लिए 250 एमएमएस अतिरिक्त लेता है, तो एरल से एसक्यूएल में कनवर्ट करने के लिए ~ 0.125ms प्रति कॉल है, जो अवास्तविक नहीं है।

दूसरा, मुझे रूबी में रेंज के आंतरिक के बारे में निश्चित नहीं है, लेकिन lower..upper रेंज और अन्य चीजों के आकार जैसे गणना कर सकता है, जो एक बड़ा प्रदर्शन हिट होगा।

क्या आप निम्न प्रदर्शन के साथ निम्नलिखित प्रदर्शन देखते हैं?

sum = Table. 
     where(:id => id). 
     where(:created_at => "BETWEEN ? and ?", lower, upper). 
     sum(:my_column) 
+1

जहां तक ​​मैं समझता हूं, .. केवल सिंटैक्टिक चीनी है कि ActiveRecord एक बयान में बदल जाता है अगर यह निर्धारित करता है कि ऑपरेंड टाइम ऑब्जेक्ट्स हैं। मैंने उस संस्करण की कोशिश की और धीमी संस्करण के समान सटीक संख्याएं प्राप्त कर रही थीं। असल में ऐसा लगता है कि उस रूपांतरण में समय लग रहा है। मैं इसे अधिक ग्रैन्युलरिटी हासिल करने के लिए प्रोफाइल करूंगा। –

+0

हाँ, इसे अभी भी एक रेंज ऑब्जेक्ट उत्पन्न करना है जो यह गुजरता है, लेकिन मुझे लगता है कि यह कोई कड़ी मेहनत नहीं करता है क्योंकि एक इटरेटर उत्पन्न नहीं होता है। क्या एआर उन्हें एकत्र करने से पहले प्रत्येक आइटम के लिए वस्तुएं बना सकता है? यह इसे धीमा कर सकता है। यद्यपि असंभव लगता है। – iHiD

+0

प्रोफाइलिंग के आधार पर, पहला संस्करण क्वेरी को निष्पादित करने में सीधे कूदता है। दूसरा संस्करण विभिन्न एआर जादू के 30 स्तरों के गहरे ढेर पर समग्र निष्पादन समय का एक अतिरिक्त 35% खर्च करता है। संस्करण धीमे संस्करण को यहां देखा जा सकता है: http://pastebin.com/bipTy3c5 सीधा एसक्यूएल संस्करण यहां है: http://pastebin.com/LysaGUTy –

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