ਤੁਹਾਡਾ SQL ਤੇਜ਼ ਹੈ ਪਰ API ਹੌਲੀ ਹੈ

ਤੁਹਾਡੀਆਂ ਡੇਟਾਬੇਸ ਕੁਐਰੀਆਂ ਤੇਜ਼ ਹਨ। ਤੁਹਾਡੀ ਕੈਸ਼ਿੰਗ (caching) ਕੰਮ ਕਰ ਰਹੀ ਹੈ। ਤੁਹਾਡੇ ਬੈਕਗ੍ਰਾਊਂਡ ਜੌਬਸ (background jobs) ਠੀਕ ਹਨ।

ਫਿਰ ਵੀ, ਤੁਹਾਡੀ API ਹਾਲੇ ਵੀ ਹੌਲੀ ਹੈ। ਤੁਹਾਡਾ CPU ਉਪਯੋਗ (usage) ਜ਼ਿਆਦਾ ਹੈ।

ਸਮੱਸਿਆ ਤੁਹਾਡੇ ਡੇਟਾਬੇਸ ਦੀ ਨਹੀਂ ਹੈ। ਸਮੱਸਿਆ Ruby ਲੇਅਰ (layer) ਦੀ ਹੈ।

ਬੋਟਲਨੇਕ (bottleneck) ਅਕਸਰ ਉਦੋਂ ਹੁੰਦਾ ਹੈ ਜਦੋਂ ਡੇਟਾ ਡੇਟਾਬੇਸ ਤੋਂ ਬਾਹਰ ਨਿਕਲ ਕੇ ਤੁਹਾਡੀ ਐਪਲੀਕੇਸ਼ਨ ਵਿੱਚ ਦਾਖਲ ਹੁੰਦਾ ਹੈ। ਇਹ ਤਿੰਨ ਮੁੱਖ ਸਮੱਸਿਆਵਾਂ ਕਾਰਨ ਹੁੰਦਾ ਹੈ:

  • ਵਧੇਰੇ (bloated) ਸੀਰੀਅਲਾਈਜ਼ੇਸ਼ਨ
  • ਬਹੁਤ ਜ਼ਿਆਦਾ ਆਬਜੈਕਟ ਅਲੋਕੇਸ਼ਨ (object allocation)
  • ਵਾਰ-ਵਾਰ ਹੋਣ ਵਾਲੀ ਕੰਪਿਊਟੇਸ਼ਨ (computation)

ਇੱਥੇ ਇਹਨਾਂ ਨੂੰ ਠੀਕ ਕਰਨ ਦੇ ਤਰੀਕੇ ਦਿੱਤੇ ਗਏ ਹਨ।

  1. ਵਧੇਰੇ ਸੀਰੀਅਲਾਈਜ਼ੇਸ਼ਨ ਨੂੰ ਰੋਕੋ

ਬਹੁਤ ਸਾਰੇ ਡਿਵੈਲਪਰ ਪੂਰੇ ਮਾਡਲਾਂ ਨੂੰ JSON ਵਿੱਚ ਬਦਲ ਦਿੰਦੇ ਹਨ।

render json: @shipments

ਜੇਕਰ ਕਿਸੇ ਸ਼ਿਪਮੈਂਟ (shipment) ਵਿੱਚ 40 ਕਾਲਮ ਹਨ ਪਰ ਤੁਹਾਡੇ ਫਰੰਟਐਂਡ (frontend) ਨੂੰ ਸਿਰਫ਼ 5 ਦੀ ਲੋੜ ਹੈ, ਤਾਂ ਤੁਸੀਂ CPU ਸਾਈਕਲਜ਼ ਬਰਬਾਦ ਕਰਦੇ ਹੋ। ਇਸ ਨਾਲ API keys ਜਾਂ ਲਾਗਤ (costs) ਵਰਗੇ ਨਿੱਜੀ ਡੇਟਾ ਲੀਕ ਹੋਣ ਦਾ ਖ਼ਤਰਾ ਵੀ ਰਹਿੰਦਾ ਹੈ।

ਹੱਲ: ਸਿਰਫ਼ ਉਹੀ ਫੀਲਡਸ (fields) ਵਾਪਸ ਕਰੋ ਜਿਨ੍ਹਾਂ ਦੀ ਤੁਹਾਨੂੰ ਲੋੜ ਹੈ।

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

ਹੋਰ ਬਿਹਤਰ ਰਫ਼ਤਾਰ ਲਈ, ਡੇਟਾ ਨੂੰ ਐਰੇਜ਼ (arrays) ਵਜੋਂ ਪ੍ਰਾਪਤ ਕਰਨ ਲਈ pluck ਦੀ ਵਰਤੋਂ ਕਰੋ। ਇਹ ਪੂਰੀ ਤਰ੍ਹਾਂ ਭਾਰੀ ActiveRecord ਆਬਜੈਕਟ ਬਣਾਉਣ ਤੋਂ ਬਚਾਉਂਦਾ ਹੈ।

  1. ਆਬਜੈਕਟ ਅਲੋਕੇਸ਼ਨ ਘਟਾਓ

Ruby ਦੁਆਰਾ ਬਣਾਇਆ ਗਿਆ ਹਰ ਆਬਜੈਕਟ ਮੈਮੋਰੀ ਦੀ ਵਰਤੋਂ ਕਰਦਾ ਹੈ। ਇੱਕ ਸਿੰਗਲ ਰਿਕੁਐਸਟ ਦੌਰਾਨ ਹਜ਼ਾਰਾਂ ਆਬਜੈਕਟ ਬਣਾਉਣ ਨਾਲ ਗਾਰਬੇਜ ਕਲੈਕਟਰ (Garbage Collector - GC) ਨੂੰ ਜ਼ਿਆਦਾ ਕੰਮ ਕਰਨਾ ਪੈਂਦਾ ਹੈ। ਇਹ ਤੁਹਾਡੇ ਪੂਰੇ ਸਿਸਟਮ ਨੂੰ ਹੌਲੀ ਕਰ ਦਿੰਦਾ ਹੈ।

ਲੂਪਸ (loops) ਦੇ ਅੰਦਰ ਨਵੇਂ ਹੈਸ਼ (hashes) ਜਾਂ ਸਟ੍ਰਿੰਗਸ (strings) ਬਣਾਉਣ ਤੋਂ ਬਚੋ।

Bad:

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

Good: ਸਟੈਟਿਕ ਡੇਟਾ ਨੂੰ ਲੂਪ ਤੋਂ ਬਾਹਰ ਲਿਜਾਓ। Ruby ਦੀ ਬਜਾਏ ਡੇਟਾਬੇਸ ਵਿੱਚ ਜ਼ਿਆਦਾ ਕੰਮ ਕਰੋ।

  1. ਵਾਰ-ਵਾਰ ਹੋਣ ਵਾਲੀ ਕੰਪਿਊਟੇਸ਼ਨ ਤੋਂ ਬਚੋ

ਜੇਕਰ ਤੁਸੀਂ ਇੱਕ ਰਿਕੁਐਸਟ ਵਿੱਚ ਇੱਕੋ ਮੈਥਡ (method) ਨੂੰ ਕਈ ਵਾਰ ਕਾਲ ਕਰਦੇ ਹੋ, ਤਾਂ ਤੁਸੀਂ ਸਮਾਂ ਬਰਬਾਦ ਕਰਦੇ ਹੋ।

Example:

def total_weight
  shipments.sum(&:weight)
end

ਜੇਕਰ ਤੁਹਾਡਾ view, helper, ਅਤੇ serializer ਸਾਰੇ ਇਸਨੂੰ ਕਾਲ ਕਰਦੇ ਹਨ, ਤਾਂ ਤੁਸੀਂ ਤਿੰਨ ਵਾਰ ਜੋੜ (sum) ਕੈਲਕੂਲੇਟ ਕਰਦੇ ਹੋ।

ਹੱਲ: ਮੈਮੋਇਜ਼ੇਸ਼ਨ (memoization) ਦੀ ਵਰਤੋਂ ਕਰੋ।

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

ਇਹ ਯਕੀਨੀ ਬਣਾਉਂਦਾ ਹੈ ਕਿ ਗਣਨਾ (math) ਇੱਕ ਰਿਕੁਐਸ ਪ੍ਰਤੀ ਸਿਰਫ਼ ਇੱਕ ਵਾਰ ਹੋਵੇ।

Summary Table:

  • ਵਧੇਰੇ ਸੀਰੀਅਲਾਈਜ਼ੇਸ਼ਨ: ਸਿਰਫ਼ ਲੋੜੀਂਦੇ ਫੀਲਡਸ ਵਾਪਸ ਕਰੋ ਜਾਂ pluck ਦੀ ਵਰਤੋਂ ਕਰੋ।
  • ਉੱਚ ਅਲੋਕੇਸ਼ਨ: ਲੂਪਸ ਵਿੱਚ ਘੱਟ ਆਬਜੈਕਟ ਬਣਾਓ।
  • ਵਾਰ-ਵਾਰ ਕੰਪਿਊਟੇਸ਼ਨ: ਨਤੀਜਿਆਂ ਨੂੰ ਦੁਬਾਰਾ ਵਰਤਣ ਲਈ ਮੈਮੋਇਜ਼ੇਸ਼ਨ ਦੀ ਵਰਤੋਂ ਕਰੋ।

ਡੇਟਾਬੇਸ ਆਪਟੀਮਾਈਜ਼ੇਸ਼ਨ (optimization) ਦਾ ਮਤਲਬ ਹੈ ਘੱਟ ਡੇਟਾ ਮੰਗਣਾ। ਐਪਲੀਕੇਸ਼ਨ ਆਪਟੀਮਾਈਜ਼ੇਸ਼ਨ ਦਾ ਮਤਲਬ ਹੈ ਡੇਟਾ ਮਿਲਣ ਤੋਂ ਬਾਅਦ ਘੱਟ ਫਾਲਤੂ ਕੰਮ ਕਰਨਾ।

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