आपकी SQL तेज़ है लेकिन API धीमी है

आपकी डेटाबेस क्वेरीज़ तेज़ हैं। आपकी कैशिंग (caching) काम कर रही है। आपके बैकग्राउंड जॉब्स (background jobs) ठीक हैं।

फिर भी, आपकी API अभी भी धीमी है। आपका CPU उपयोग (usage) अधिक है।

समस्या आपका डेटाबेस नहीं है। समस्या Ruby लेयर (layer) है।

बॉटलनेक (bottleneck) अक्सर तब होता है जब डेटा डेटाबेस से बाहर निकलता है और आपके एप्लिकेशन में प्रवेश करता है। यह तीन मुख्य समस्याओं के कारण होता है:

  • भारी सीरियलाइजेशन (Bloated serialization)
  • अत्यधिक ऑब्जेक्ट एलोकेशन (Excessive object allocation)
  • बार-बार होने वाली गणना (Repeated computation)

इन्हें ठीक करने का तरीका यहाँ दिया गया है।

1. भारी सीरियलाइजेशन (Bloated Serialization) को रोकें

कई डेवलपर्स पूरे मॉडल्स को JSON में बदल देते हैं।

render json: @shipments

यदि किसी शिपमेंट में 40 कॉलम हैं लेकिन आपके फ्रंटएंड को केवल 5 की आवश्यकता है, तो आप CPU साइकल (cycles) बर्बाद करते हैं। आप API कीज़ या लागत जैसे निजी डेटा के लीक होने का जोखिम भी उठाते हैं।

समाधान: केवल वही फ़ील्ड्स लौटाएं जिनकी आपको आवश्यकता है।

render json: @shipments.as_json(only: [:id, :tracking_no, :status])

और भी बेहतर गति के लिए, डेटा को ऐरे (arrays) के रूप में प्राप्त करने के लिए pluck का उपयोग करें। यह भारी ActiveRecord ऑब्जेक्ट्स बनाने से पूरी तरह से बचाता है।

2. ऑब्जेक्ट एलोकेशन (Object Allocation) कम करें

Ruby द्वारा बनाया गया प्रत्येक ऑब्जेक्ट मेमोरी खर्च करता है। एक ही रिक्वेस्ट के दौरान हजारों ऑब्जेक्ट्स बनाने से गार्बेज कलेक्टर (Garbage Collector - GC) को अधिक मेहनत करनी पड़ती है। इससे आपका पूरा सिस्टम धीमा हो जाता है।

लूप के अंदर नए हैश (hashes) या स्ट्रिंग्स (strings) बनाने से बचें।

गलत (Bad):

@shipments.map do |s|
  { label: "#{s.tracking_no} - #{s.status.upcase}" }
end

सही (Good): स्टैटिक डेटा को लूप के बाहर ले जाएं। Ruby के बजाय डेटाबेस में अधिक काम करें।

3. बार-बार होने वाली गणना (Repeated Computation) से बचें

यदि आप एक ही रिक्वेस्ट में एक ही मेथड को कई बार कॉल करते हैं, तो आप समय बर्बाद करते हैं।

उदाहरण:

def total_weight
  shipments.sum(&:weight)
end

यदि आपका व्यू (view), हेल्पर (helper) और सीरियलाइज़र (serializer) सभी इसे कॉल करते हैं, तो आप तीन बार योग (sum) की गणना करते हैं।

समाधान: मेमोइज़ेशन (memoization) का उपयोग करें।

def total_weight
  @total_weight ||= shipments.sum(&:weight)
end

यह सुनिश्चित करता है कि गणितीय गणना प्रति रिक्वेस्ट केवल एक बार हो।

सारांश तालिका (Summary Table):

समस्या समाधान
भारी सीरियलाइजेशन (Bloated serialization) केवल आवश्यक फ़ील्ड्स लौटाएं या pluck का उपयोग करें।
उच्च एलोकेशन (High allocation) लूप में कम ऑब्जेक्ट्स बनाएं।
बार-बार होने वाली गणना (Repeated computation) परिणामों का पुन: उपयोग करने के लिए मेमोइज़ेशन का उपयोग करें।

डेटाबेस ऑप्टिमाइज़ेशन का अर्थ है कम डेटा मांगना। एप्लिकेशन ऑप्टिमाइज़ेशन का अर्थ है डेटा मिलने के बाद कम अनावश्यक काम (busywork) करना।

Source: https://dev.to/danewu/your-sql-is-fast-but-the-api-is-slow-its-the-ruby-layer-2fno