ActiveRecord: आकार बनाम गणना


201

रेल में, आप दोनों Model.sizeऔर का उपयोग करके रिकॉर्ड की संख्या पा सकते हैं Model.count। यदि आप अधिक जटिल प्रश्नों से निपट रहे हैं, तो क्या एक विधि का दूसरे पर उपयोग करने का कोई फायदा है? वे कैसे अलग हैं?

उदाहरण के लिए, मेरे पास फ़ोटो वाले उपयोगकर्ता हैं। अगर मैं उपयोगकर्ताओं की एक तालिका दिखाना चाहता हूं और उनके पास कितनी तस्वीरें हैं, तो क्या उनके कई उदाहरण user.photos.sizeतेज़ या धीमे चलेंगे user.photos.count?

धन्यवाद!

जवाबों:


344

आप पढ़ना चाहिए कि , यह अभी भी मान्य है।

आप अपनी आवश्यकताओं के आधार पर आपके द्वारा उपयोग किए जाने वाले फ़ंक्शन को अनुकूलित करेंगे।

मूल रूप से:

  • यदि आप पहले से ही सभी प्रविष्टियों को लोड करते हैं, कहते हैं User.all, तो आपको lengthएक और डीबी क्वेरी से बचने के लिए उपयोग करना चाहिए

  • यदि आपने कुछ भी लोड नहीं किया है, countतो अपने db पर एक गणना क्वेरी बनाने के लिए उपयोग करें

  • यदि आप इन विचारों से परेशान नहीं होना चाहते हैं, तो उपयोग करें sizeजो अनुकूल होगा


35
अगर sizeवैसे भी स्थिति के अनुकूल है, तो इसके लिए lengthऔर क्या जरूरत है count?
sscirrus

27
@sscirus - ताकि sizeआप कॉल करने पर उन्हें कॉल कर सकें size(इसके बाद यह निर्धारित होता है कि किसे कॉल करना है)।
बाटकिंस

35
हालाँकि, आकार में चूक के साथ सावधान रहें। उदाहरण के लिए आप संबंध के माध्यम से जा रहा है, यानी बिना एक नया रिकॉर्ड बनाने यदि Comment.create(post_id: post.id), अपने post.comments.sizeइच्छा नहीं, तारीख तक रखें जब post.comments.countइच्छा। तो जरा संभल कर।
मर्ब्रदो

14
इसके अलावा, यदि आप एक संबंध के माध्यम से कई वस्तुओं का निर्माण करते हैं: company.devices.build(:name => "device1"); company.devices.build(:name => "device2")तो, company.devices.sizeऔर .lengthआपके द्वारा बनाई गई वस्तुओं की संख्या शामिल होगी लेकिन सहेजे नहीं गए हैं, .countकेवल डेटाबेस से गिनती की रिपोर्ट करेंगे।
शॉन जे। गोफ

6
@sscirrus, आकार एक खतरनाक कमांड है क्योंकि यह स्वचालित है, कभी-कभी आप db को फिर से क्वेरी करना चाहते हैं।
एलेक्स सी

79

अन्य उत्तर के रूप में राज्य:

  • countSQL COUNTक्वेरी निष्पादित करेगा
  • length परिणामी सरणी की लंबाई की गणना करेगा
  • size अत्यधिक प्रश्नों से बचने के लिए दोनों में से सबसे उपयुक्त चुनने की कोशिश करेंगे

लेकिन एक बात और है। हमने एक ऐसे मामले पर ध्यान दिया, जहां / पूरी तरह sizeसे अलग-अलग कार्य करता है , और मैंने सोचा कि मैं इसे साझा करूंगा क्योंकि यह दुर्लभ है जिसकी अनदेखी की जा सकती है।countlength

  • यदि आप :counter_cacheकिसी has_manyएसोसिएशन पर sizeउपयोग करते हैं, तो सीधे कैश्ड गिनती का उपयोग करेंगे, और अतिरिक्त क्वेरी नहीं करेंगे।

    class Image < ActiveRecord::Base
      belongs_to :product, counter_cache: true
    end
    
    class Product < ActiveRecord::Base
      has_many :images
    end
    
    > product = Product.first  # query, load product into memory
    > product.images.size      # no query, reads the :images_count column
    > product.images.count     # query, SQL COUNT
    > product.images.length    # query, loads images into memory

इस व्यवहार को रेल गाइड में प्रलेखित किया गया है , लेकिन मैं या तो इसे पहली बार याद किया या इसके बारे में भूल गया।


वास्तव में, 5.0.0.beta1 रेल से पहले, यह व्यवहार तब भी ट्रिगर किया जाएगा, भले ही कोई _countकॉलम हो ( counter_cache: trueएसोसिएशन पर निर्देश के बिना )। यह github.com/rails/rails/commit/e0cb21f5f7
cbliard

8

कभी-कभी size"गलत को चुनता है" और एक हैश लौटाता है (जो कि क्या countकरेगा)

उस स्थिति में, हैश के बजाय पूर्णांकlength प्राप्त करने के लिए उपयोग करें ।


मैंने has_many उदाहरण से एक संग्रह पर '.Size' का उपयोग किया और भले ही संग्रह में एक रिकॉर्ड था, आकार एक '0' वापस कर रहा था। .Count का उपयोग करके '1' का सही मान लौटाया गया।
दाखिला

4

tl; डॉ

  • यदि आप जानते हैं कि आपको डेटा उपयोग की आवश्यकता नहीं होगी count
  • यदि आप जानते हैं कि आप डेटा का उपयोग करेंगे या उपयोग करेंगे length
  • यदि आप नहीं जानते कि आप क्या कर रहे हैं, तो उपयोग करें size...

गिनती

Select count(*)...DB को एक प्रश्न भेजने का संकल्प करता है । यदि आपको डेटा की आवश्यकता नहीं है, तो जाने का तरीका, लेकिन सिर्फ गिनती।

उदाहरण: नए संदेशों की गिनती, कुल तत्व जब केवल एक पृष्ठ प्रदर्शित होने जा रहा है, आदि।

लंबाई

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

उदाहरण: पूरी तरह भरी हुई मेज का सारांश, प्रदर्शित आंकड़ों के शीर्षक आदि।

आकार

यह जांचता है कि क्या डेटा लोड किया गया था (यानी पहले से ही रेल में) यदि ऐसा है, तो बस इसे गिनें, अन्यथा इसे गणना कहते हैं। (प्लस में पहले से ही अन्य प्रविष्टियों में वर्णित नुकसान)।

def size
  loaded? ? @records.length : count(:all)
end

समस्या क्या है?

यदि आप सही क्रम में ऐसा नहीं करते हैं तो आप डीबी को दो बार मार सकते हैं (जैसे कि यदि आप तालिका के शीर्ष पर एक तालिका में तत्वों की संख्या को प्रस्तुत करते हैं, तो प्रभावी रूप से डीबी को भेजे गए 2 कॉल होंगे)।


3

निम्नलिखित रणनीतियाँ सभी COUNT(*)क्वेरी करने के लिए डेटाबेस पर कॉल करती हैं ।

Model.count

Model.all.size

records = Model.all
records.count

निम्नलिखित उतना कुशल नहीं है क्योंकि यह डेटाबेस से सभी रिकॉर्ड को रूबी में लोड कर देगा, जो तब संग्रह के आकार को गिनता है।

records = Model.all
records.size

यदि आपके मॉडल में एसोसिएशन हैं और आप संबंधित ऑब्जेक्ट्स की संख्या (जैसे @customer.orders.size) खोजना चाहते हैं , तो आप डेटाबेस क्वेरी (डिस्क रीड्स) से बच सकते हैं। एक काउंटर कैश का उपयोग करें और रेल कैश मूल्य को अद्यतित रखेंगे, और sizeविधि के जवाब में उस मूल्य को वापस करेंगे ।


2
दोनों Model.all.sizeऔर Model.all.countएक उत्पन्न countरेल 4 और इसके बाद के संस्करण में क्वेरी। इसका असली फायदा sizeयह है कि अगर एसोसिएशन पहले ही लोड हो जाता है तो यह गणना क्वेरी उत्पन्न नहीं करता है। रेल 3 और नीचे में, मेरा मानना Model.allहै कि कोई संबंध नहीं है, इसलिए सभी रिकॉर्ड पहले से लोड हैं। यह उत्तर पुराना हो सकता है और मैं इसे हटाने का सुझाव देता हूं।
दमन ऐ

1

मैंने आकार फ़ंक्शन का उपयोग करने की सिफारिश की है।

class Customer < ActiveRecord::Base
  has_many :customer_activities
end

class CustomerActivity < ActiveRecord::Base
  belongs_to :customer, counter_cache: true
end

इन दो मॉडलों पर विचार करें। ग्राहक के पास कई ग्राहक गतिविधियाँ हैं।

यदि आप has_many एसोसिएशन पर एक: counter_cache का उपयोग करते हैं, तो आकार सीधे कैश्ड गणना का उपयोग करेगा, और बिल्कुल भी अतिरिक्त क्वेरी न करें।

एक उदाहरण पर विचार करें: मेरे डेटाबेस में, एक ग्राहक के पास 20,000 ग्राहक गतिविधियां हैं और मैं प्रत्येक गणना, लंबाई और आकार विधि के साथ उस ग्राहक की ग्राहक गतिविधियों के रिकॉर्ड की संख्या गिनने का प्रयास करता हूं। इन सभी तरीकों की बेंचमार्क रिपोर्ट के नीचे।

            user     system      total        real
Count:     0.000000   0.000000   0.000000 (  0.006105)
Size:      0.010000   0.000000   0.010000 (  0.003797)
Length:    0.030000   0.000000   0.030000 (  0.026481)

इसलिए मैंने पाया कि रिकॉर्ड की संख्या की गणना करने के लिए counter_cache Size सबसे अच्छा विकल्प है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.