Forum: Italian Ruby user group Ottmizzazione delle ricerche nel DB

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Luigi M. (Guest)
on 2009-06-09 12: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
Andrea L. (Guest)
on 2009-06-09 13:29
Luigi M. 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.
Luigi M. (Guest)
on 2009-06-10 17: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
Luigi M. (Guest)
on 2009-06-10 19:04
>Andrea L. 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
Luigi M. (Guest)
on 2009-06-10 19:10
Ok,
law.votes.count(:conditions=>'yes') l'ho risolto.

Continuo a non capire il:

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


Luigi
Luigi M. (Guest)
on 2009-06-10 20: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 L.:

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


Grazie sempre

Luigi
Andrea L. (Guest)
on 2009-06-11 02:45
Luigi M. 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 L.:
>
> 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
This topic is locked and can not be replied to.