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.
- 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.
- 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.
- 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
