Il tuo SQL è veloce, ma l'API è lenta

Le tue query al database sono veloci. Il caching funziona. I tuoi job in background vanno bene.

Eppure, la tua API è ancora lenta. L'utilizzo della CPU è elevato.

Il problema non è il database. Il problema è lo strato Ruby.

Il collo di bottiglia si verifica spesso dopo che i dati lasciano il database ed entrano nella tua applicazione. Ciò accade a causa di tre problemi principali:

  • Serializzazione pesante
  • Allocazione eccessiva di oggetti
  • Calcoli ripetuti

Ecco come risolverli.

  1. Smetti di usare una serializzazione pesante

Molti sviluppatori trasformano interi modelli in JSON.

render json: @shipments

Se una spedizione ha 40 colonne ma il tuo frontend ne richiede solo 5, sprechi cicli di CPU. Inoltre, rischi di esporre dati privati come chiavi API o costi.

La soluzione: restituisci solo i campi necessari.

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

Per una velocità ancora maggiore, usa pluck per recuperare i dati come array. Questo evita completamente la creazione di pesanti oggetti ActiveRecord.

  1. Riduci l'allocazione di oggetti

Ogni oggetto creato da Ruby ha un costo in termini di memoria. Creare migliaia di oggetti durante una singola richiesta costringe il Garbage Collector (GC) a lavorare di più. Questo rallenta l'intero sistema.

Evita di creare nuovi hash o stringhe all'interno dei cicli.

Sbagliato:

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

Corretto: Sposta i dati statici all'esterno del ciclo. Sposta parte del lavoro sul database invece di farlo in Ruby.

  1. Evita calcoli ripetuti

Se chiami lo stesso metodo più volte in una singola richiesta, sprechi tempo.

Esempio:

def total_weight
  shipments.sum(&:weight)
end

Se la tua view, il tuo helper e il tuo serializer chiamano tutti questo metodo, calcolerai la somma tre volte.

La soluzione: usa la memoization.

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

Questo assicura che il calcolo avvenga una sola volta per richiesta.

Tabella riassuntiva:

  • Serializzazione pesante: Restituisci solo i campi necessari o usa pluck.
  • Alta allocazione: Crea meno oggetti nei cicli.
  • Calcoli ripetuti: Usa la memoization per riutilizzare i risultati.

L'ottimizzazione del database significa richiedere meno dati. L'ottimizzazione dell'applicazione significa svolgere meno lavoro superfluo una volta ottenuti i dati.

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