homeASCIIcasts

22: Caricamento dati preventivo (eager loading) 

(view original Railscast)

Other translations: En

Other formats:

Written by Andrea Salicetti

Un buon punto di partenza per cominciare quando si vogliono aumentare le prestazioni delle vostre applicazioni Rails è dare un’occhiata agli accessi al database. Ridurre il numero di query fatte al database può incrementare la velocità delle vostre applicazioni in modo significativo. Un modo per farlo è quello di adottare una tecnica nota con il nome di eager loading.

I nostri modelli applicativi Task e Project.

La pagina di sopra mostra un numero consistente di task, e il progetto a cui ognuno di essi appartiene. Nel nostro TaskController, otteniamo tutti questi task e iteriamo su ciascuno di essi nella vista:

  <h1>Tasks</h1>
  <ul>
  <% @tasks.each do |task| %>
    <li><%= link_to task.name, task %> in <%= task.project.name %></li>
  <% end %>
  </ul>The view code for the Tasks index page. 
  

La pagina prende il nome del task e poi il nome dei suoi progetti attraverso l’associazione. Il problema nell’uso di questo approccio è che ogni volta che si ottiene il nome di un progetto del task, viene generata una query SQL. Ne si può avere conferma controllando i log di sviluppo.

   Project Load (0.2ms)   SELECT * FROM "projects" WHERE ("projects"."id" = 60) 
   CACHE (0.0ms)   SELECT * FROM "projects" WHERE ("projects"."id" = 60) 
   CACHE (0.0ms)   SELECT * FROM "projects" WHERE ("projects"."id" = 60) 
   CACHE (0.0ms)   SELECT * FROM "projects" WHERE ("projects"."id" = 60) 
   CACHE (0.0ms)   SELECT * FROM "projects" WHERE ("projects"."id" = 60)
  

La nostra richiesta causa ripetute chiamate al database.

Possiamo vedere dai log che viene eseguita la stessa chiamata tante volte quanti sono i nomi dei progetti. Rails ci aiuta a ridurre il numero di chiamate, facendo cache delle richieste e recuperando le richieste ripetute dalla cache, piuttosto che dal database. Il sistema di caching è stato introdotto con Rails 2.0; se facessimo la stessa richiesta con Rails 1.x, ogni richiesta per il nome di un progetto associato al task comporterebbe una richiesta al database.

Il sistema di caching è utile, ma l’eager loading riduce le chiamate al database ulteriormente. Lo possiamo abilitare facendo una piccola modifica al TasksController:

  class TasksController < ApplicationController
    def index
      @tasks = Task.find(:all, :include => :project)
    end
  end
  

Ciò che abbiamo fatto sopra è di aggiungere un parametro alla linea che recupera tutti i task, in modo tale che nel recupero si porti dietro anche i progetti associati. La ragione per cui nel codice abbiamo usato il simbolo al singolare (:project), anzichè :projects è che usiamo il nome dell’associazione, e nel modello Task cè scritto belongs_to => :project. Ora, se ricarichiamo la pagina e controlliamo i log, vediamo che il numero di richieste al database si è ridotto da 101 a 2, con un conseguente aumento delle performance della nostra applicazione.

Inclusione di più di una associazione

Oltre ad appartenere ad un Project, il nostro modello Task ha anche un’altra associazione con il modello Comment.

  class Task < ActiveRecord::Base
    belongs_to :project
    has_many :comments
  end
  

Possiamo portarci dietro i commenti di un task insieme al suo progetto di appartenenza, includendo i nomi di entrambe le associazioni in un array. (notate che per i commenti usiamo il plurale poichè questo è ora il nome dell’associazione.)

  class TasksController < ApplicationController
    def index
      @tasks = Task.find(:all, :include => [:project, :comments])
    end
  end
  

Potremmo fare uso perfino di associazioni ancor più complesse. Se il nostro modello Comment fosse così …

  class Comment < ActiveRecord::Base
    belongs_to :task
    belongs_to :user
  end
  

…potremmo portarci dietro anche gli utenti associati ai commenti, usando un hash:

  @tasks = Task.find(:all, :include => [:project, {:comments => :user }])
  

L’utilizzo dell’eager loading è un potente modo per ridurre gli accessi al database delle vostre applicazioni Rails. Ci sono più informazioni a riguardo nel sito delle API Rails su http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html.