Le prestazioni sono uno degli aspetti più importanti da tenere in considerazione quando si sviluppano applicazioni web. Analizzare il modo in cui i dati vengono recuperati da un database è un buon punto di partenza per cercare miglioramenti. In questo articolo troverete esempi su come migliorare le prestazioni utilizzando funzioni aggregate e filtrando i dati a livello di database.
Per cominciare, un po' di contesto
Questo articolo è ispirato a un problema reale che mi è capitato di dover affrontare. Affrontarlo mi ha insegnato molto e lo tengo ancora come riferimento nella mia mente. Credo che gli esempi siano una buona risorsa di apprendimento, in quanto possono chiarire molte cose. In questo articolo, vorrei condividere con voi alcuni esempi di utilizzo dei metodi di interrogazione di Active Record.
Per non introdurre dettagli specifici del dominio, utilizzerò un'applicazione di esempio per una libreria per illustrare gli esempi. È tutto abbastanza semplice, come mostra il diagramma seguente. Abbiamo quattro tabelle: autori, libri, utenti e noleggi. Un utente può prendere in prestito molti libri e un libro può essere preso in prestito da molti utenti, quindi abbiamo bisogno di una tabella di unione per modellare le relazioni molti-a-molti. Nel nostro caso, si tratta della tabella Noleggi. Vi memorizziamo anche alcune informazioni aggiuntive, come le date di prestito e di restituzione. Un autore può avere molti libri assegnati al suo nome. Un libro ha anche un attributo che ne definisce il genere.
Statistiche di lettura degli utenti
Il compito era quello di preparare le statistiche per un singolo utente, in modo da poter dire quanti libri di ogni genere sono stati presi in prestito. La mia prima idea è stata quella di recuperare tutti i libri che sono stati presi in prestito dall'utente, raggrupparli per genere e poi fare la mappatura, in modo che a ogni genere sia assegnato un numero di libri invece di un elenco. Ecco cosa mi è venuto in mente:
Sebbene questo approccio funzioni e abbia un aspetto pulito, non sfrutta tutte le possibilità offerte dai metodi di interrogazione di Active Record. Grazie ad essi, siamo in grado di filtrare e aggregare i dati a livello di database senza utilizzare direttamente l'SQL grezzo nel nostro codice. Operare a livello di db aumenta anche la nostra efficienza.
Nell'esempio precedente, possiamo usare il metodo group al posto del group di Rubyper metodo. Applicherà il GRUPPOBY alla query tSQL. Inoltre, il metodo di mappatura e dimensione può essere sostituito con una funzione di aggregazione del conteggio. Alla fine si ottiene una query di questo tipo:
Book.joins(:rentals).where(rentals: { user: user }).group(:genre).count(:books)
Sembra ancora più semplice!
Altri esempi utili
Di seguito troverete altri modi di utilizzare i metodi di interrogazione che ritengo valga la pena conoscere.
Invito per gli utenti inattivi
COMPITO: Filtrare gli utenti che non hanno mai preso in prestito un libro o che lo hanno fatto più di un anno fa.
Potremmo recuperare tutti gli utenti includendo gli affitti associati e poi filtrarli utilizzando il metodo select.
User.includes(:rentals).select do |user|
user.rentals.empty? || utente.affitti.nessuno? { |noleggio| noleggio.data_inizio >= Data.oggi - 1.anno }
fine
Ma, ovviamente, non è necessario recuperare tutto. Utilizzando i metodi di interrogazione, possiamo filtrare a livello di db. Per prima cosa, selezioniamo gli utenti che hanno preso in prestito alcuni libri nell'ultimo anno e poi escludiamoli dalla selezione finale.
COMPITO: trovare gli autori con uno o zero libri in prestito
Farlo con il metodo select è semplicissimo, ma ancora una volta non c'è bisogno di operare su un insieme così grande di dati, perché il db può filtrarli per noi:
È importante ricordare una cosa quando si utilizzano le left_join (e le outer join in generale). Se ci sono record nella tabella di sinistra (qui: autori) che non hanno record corrispondenti nella tabella di destra (qui: libri), le colonne della tabella di destra saranno popolate con valori nulli.
Poiché abbiamo bisogno anche di autori con un libro assegnato nel sistema, ci sono alcune operazioni in più da fare. Dovremo raggruppare, contare e aggiungere una condizione. Ecco come mettere insieme il tutto:
La condizione viene dopo la funzione di aggregazione, quindi dobbiamo usare la clausola HAVING invece della clausola WHERE per specificarla.
I metodi di interrogazione di Active Record meritano di essere controllati quando si pensa alle prestazioni dell'applicazione. Possono semplificare il codice e renderlo più veloce. Spero che gli esempi condivisi vi aiutino a esplorare le possibilità offerte dai metodi di interrogazione.