మీ SQL వేగంగా ఉంది కానీ API నెమ్మదిగా ఉంది

మీ డేటాబేస్ క్వెరీల (queries) వేగంగా ఉన్నాయి. మీ క్యాషింగ్ (caching) సరిగ్గా పనిచేస్తోంది. మీ బ్యాక్‌గ్రౌండ్ జాబ్స్ (background jobs) కూడా బాగున్నాయి.

అయినప్పటికీ, మీ API ఇంకా నెమ్మదిగానే ఉంది. మీ CPU వినియోగం (usage) ఎక్కువగా ఉంది.

సమస్య మీ డేటాబేస్‌లో లేదు. సమస్య Ruby లేయర్‌లో ఉంది.

డేటా డేటాబేస్ నుండి బయటకు వచ్చి మీ అప్లికేషన్‌లోకి ప్రవేశించిన తర్వాత తరచుగా బాటిల్‌నెక్ (bottleneck) ఏర్పడుతుంది. ఇది ప్రధానంగా మూడు సమస్యల వల్ల జరుగుతుంది:

  • అనవసరమైన సీరియలైజేషన్ (Bloated serialization)
  • అధిక ఆబ్జెక్ట్ అలోకేషన్ (Excessive object allocation)
  • పదేపదే జరిగే గణనలు (Repeated computation)

వీటిని ఎలా పరిష్కరించాలో ఇక్కడ చూడండి.

  1. అనవసరమైన సీరియలైజేషన్‌ను నివారించండి (Stop Bloated Serialization)

చాలా మంది డెవలపర్లు పూర్తి మోడల్స్‌ను JSONగా మారుస్తారు.

render json: @shipments

ఒక షిప్‌మెంట్‌కు 40 కాలమ్స్ ఉండి, మీ ఫ్రంటెండ్ (frontend) కేవలం 5 మాత్రమే కావాలనుకుంటే, మీరు అనవసరంగా CPU సైకిల్స్‌ను వృథా చేసినట్లే. అంతేకాకుండా, API కీలు లేదా ఖర్చుల వంటి ప్రైవేట్ డేటా లీక్ అయ్యే ప్రమాదం కూడా ఉంది.

పరిష్కారం: మీకు అవసరమైన ఫీల్డ్స్‌ను మాత్రమే తిరిగి పంపండి (return).

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

ఇంకా మెరుగైన వేగం కోసం, డేటాను అర్రేలుగా (arrays) పొందడానికి pluck ఉపయోగించండి. దీనివల్ల భారీ ActiveRecord ఆబ్జెక్ట్‌లను నిర్మించాల్సిన అవసరం పూర్తిగా ఉండదు.

  1. ఆబ్జెక్ట్ అలోకేషన్‌ను తగ్గించండి (Reduce Object Allocation)

Ruby సృష్టించే ప్రతి ఆబ్జెక్ట్ మెమరీని వినియోగిస్తుంది. ఒకే రిక్వెస్ట్ సమయంలో వేల సంఖ్యలో ఆబ్జెక్ట్‌లను సృష్టించడం వల్ల గార్బేజ్ కలెక్టర్ (Garbage Collector - GC) మరింత కష్టపడాల్సి వస్తుంది. ఇది మీ మొత్తం సిస్టమ్‌ను నెమ్మదింపజేస్తుంది.

లూప్‌ల (loops) లోపల కొత్త హాష్‌లు (hashes) లేదా స్ట్రింగ్స్‌ను (strings) సృష్టించకండి.

Bad:

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

Good: స్టాటిక్ డేటాను లూప్ వెలుపల ఉంచండి. Rubyలో కంటే డేటాబేస్‌లోనే ఎక్కువ పని చేయించండి.

  1. పదేపదే జరిగే గణనలను నివారించండి (Avoid Repeated Computation)

ఒకే రిక్వెస్ట్‌లో ఒకే మెథడ్‌ను పదేపదే పిలిస్తే, మీరు సమయాన్ని వృథా చేసినట్లే.

Example:

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