Forum: Italian Ruby user group Ottmizzazione delle ricerche nel DB

Posted by Luigi Maresca (luigi-s-w-net)
on 2009-06-09 10:44
Salve ragazzi,
ho costruito un aplicazione dove sono presenti 3 tabelle:
1 - contiene le leggi
2 - contiene gli utenti
3 - contiene i voti degli utenti sugli articoli

la terza tabella è di collegamento alle prime due dato che ogni rigo
(ID) contiene l'id della legge, l'id dell'utente e il voto.

Nella home vengono riportati tutti gli articoli e per ogni articolo
vengono raccolti i numeri di voti positivi e negativi.

I modelli definiscono le varie associazioni:

laws-> has_many:votes

users -> has_many:laws

votes ->
belongs_to :user
belongs_to :laws

nel controller Law definisco la vista index:
def index
   @votes=Vote
   @laws=Law.find(:all,:conditions=>'public',:order=>'updated desc')
end

Come potete notare @votes non fa alcuna ricerca specifica ma aggancia
l'intera tabella.

Questo mi è necessario perché poi nel ciclo for, della vista index, che
elenca tutte le leggi per ogni legge devo contare all'interno di @votes
il numero di voti:
---------
<%for law in @laws-%>
<%=law.title-%>
....
<%=@votes.count(:all,:conditions=>"law_id=#{law.id} and yes")-%>
<%end-%>
----------

Quindi per ogni articolo visualizzato devo fare un'interrogazione nel DB
o meglio nell'array @votes.

Veniamo alla domanda:

esiste un modo più efficace e meno impegnativo per la CPU?

mi sapete dare qualche suggerimento per migliorare il codice?

Grazie mille

Luigi
Posted by Andrea Longhi (andrea)
on 2009-06-09 11:29
Luigi Maresca wrote:

>    @votes=Vote
>    @laws=Law.find(:all,:conditions=>'public',:order=>'updated desc')
> end
> 
> Come potete notare @votes non fa alcuna ricerca specifica ma aggancia
> l'intera tabella.

la classe Vote è dispobilile anche nella vista, senza bisogno di 
referenziarla con una variabile di istanza. Ti ricordo pero' che nella 
vista la logica non ci dovrebbe stare, il suo posto è il controller o 
alla peggio l'helper.

> <%for law in @laws-%>
> <%=law.title-%>
> ....
> <%=@votes.count(:all,:conditions=>"law_id=#{law.id} and yes")-%>

Che significa quel and yes?
Comunque, visto che hai dichiarato le associazioni necessarie puoi usare 
direttamente law.votes.count invece di quella robaccia :)

Nel controller puoi usare
@laws=Law.find(:all, :conditions=>'public', :order=>'updated desc', 
:include => :votes)
per tirarti su anche tutti i voti associati alle leggi, ti risparmi un 
po' di query. Quel :conditions => 'public' e' inquietante.

Se vuoi ottimizzare ulteriormente puoi usare una counter cache, trovi 
tutorial in rete o cercati un libro recente su rails, penso che ti 
aiuterebbe molto.
Posted by Luigi Maresca (luigi-s-w-net)
on 2009-06-10 15:22
Grazie mille,
perdonatemi ma non ho ancora avuto il tempo di provare.

'and yes' serve a contare i voti positivi, sarebbe yes=true.

Ma perché :conditions=>'public' è inquitante???

Grazie

Luigi
Posted by Luigi Maresca (luigi-s-w-net)
on 2009-06-10 17:04
>Andrea Longhi wrote:
> Che significa quel and yes?
> Comunque, visto che hai dichiarato le associazioni necessarie puoi usare 
> direttamente law.votes.count invece di quella robaccia :)


Ciao Andrea,
law.votes.count non funziona correttamente dato che mi calcola tutti i 
voti sia i positivi che i negativi.

Questo perché nella tabella votes esiste la voce yes (tinyint (1)).

E' per questo che nel codice che avevo scritto c'è '... and yes'.

Come faccio? (mi piace tanto quel law.votes.count)

Perché :conditions=>'public' è inquitante???

Grazie mille

Luigi
Posted by Luigi Maresca (luigi-s-w-net)
on 2009-06-10 17:10
Ok,
law.votes.count(:conditions=>'yes') l'ho risolto.

Continuo a non capire il:

Perché :conditions=>'public' è inquitante???


Luigi
Posted by Luigi Maresca (luigi-s-w-net)
on 2009-06-10 18:06
Un'altra domanda:
ma un comando di questo tipo

law.votes.count

implica una ricerca nel DB così come il comando

@votes.count(:all,:conditions=>"law_id=#{law.id} and yes")

?

cioè dal punto di vista dello sfruttamento del DB è lo stesso?


e inoltre c'è differenza, sempre dal punto di vista dello sfruttamento 
del DB, se la ricerca viene eseguita nel controller oppure nella vista?

Per Andrea Longhi:

Perché :conditions=>'public' è inquitante???


Grazie sempre

Luigi
Posted by Andrea Longhi (andrea)
on 2009-06-11 00:45
Luigi Maresca wrote:
> Un'altra domanda:
> ma un comando di questo tipo
> 
> law.votes.count
> 
> implica una ricerca nel DB così come il comando
> 
> @votes.count(:all,:conditions=>"law_id=#{law.id} and yes")
> 
> ?

Dipende. Se hai già raccolto i voti associati a quella legge no. Per 
toglierti questi dubbi è sufficiente guardare il file development.log 
mentre smanetti con l'applicazione nel browser, o ancora meglio nella 
console in casi come questo. Da teminale se sei su un sistema unix-like: 
tail -f log/development.log

> e inoltre c'è differenza, sempre dal punto di vista dello sfruttamento 
> del DB, se la ricerca viene eseguita nel controller oppure nella vista?

No, ma certe cose nelle viste non ci dovrebbero essere.

> Per Andrea Longhi:
> 
> Perché :conditions=>'public' è inquitante???

Perche' non è il massimo della chiarezza, come lo yes del resto... 
pessimo nome per un campo, non trovi? Sai, finche' il codice lo legge 
solo chi lo scrive va  bene qualsiasi schifezza basta che funzioni(si fa 
per dire, quando dopo 6 mesi rileggi il tuo stesso codice ti voglio 
proprio vedere se capisci al volo cosa significa il campo yes), ma se lo 
devono leggere anche gli altri... beh meglio che sia chiaro.
Io espliciterei la condizione con

@laws = Law.all(:conditions => {:public => true})

o ancora meglio metterei un named_scope nel modello:

class Law < ActiveRecord::Base
  named_scope :public, :conditions => {:public => true}
  # ...
end

così quando scrivi Law.public ti trova tutte le leggi pubbliche... 
potresti fare la stessa cosa coi voti, qualcosa del tipo:

class Votes < ActiveRecord...
  named_scope :positive, :conditions => {:yes => true}
  #....
end
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.