2011-01-15 10 views
5

Come posso ottimizzare i miei query SQL, di ignorare situazioni come questa:counter_cache ottimizzazione has_many_through SQL, ridurre il numero di query SQL

Meeting.find (5) .users.size => SELECT COUNT (*) dA DOVE ... ...

User.find (123) .meetings.size => SELECT COUNT (*) FROM ... Dove ...

non ho idea di come utilizzare counter_cache qui.

Ecco il mio modello di relazione:

class Meeting < ActiveRecord::Base 
    has_many :meeting_users 
    has_many :users, :through => meeting_users 
end 

class User < ActiveRecord::Base 
    has_many :meeting_users 
    has_many :meetings, :through => meeting_users 
end 

class Meeting_user < ActiveRecord::Base 
    belongs_to :meeting 
    belongs_to :user 
end 

Quali sono le soluzioni più ottimali?

E come implementare counter_cache qui?

+0

Qualsiasi cosa qui ti impedisce di fare qualcosa come MeetingUser.where (: meeting_id => 5,: user_id => 123) .size per entrambe le situazioni? Almeno in tal caso si sarebbe in grado di sfruttare la memorizzazione nella cache SQL query. L'implementazione predefinita di counter_cache non ti aiuterà veramente in questo tipo di situazione. – jmcnevin

+1

Penso che tu abbia torto. counter_cache aiuterà qui. Ad esempio, quando si esegue il rendering di un elenco di utenti nella vista e in ciascuna riga viene visualizzato il numero di riunioni di ciascun utente? Con counter_cache questa sarà una query SQL, senza che sia 1 + n * Users.size – astropanic

risposta

1

Per quanto ne so non è possibile utilizzare counter_cache con le associazioni through, ecco perché è necessario incrementarlo manualmente.

Per esempio (non testata):

class MeetingUser < ActiveRecord::Base 

    ... 

    after_create { |record| 
    Meeting.increment_counter(:users_count, record.meeting.id) 
    } 

    after_destroy { |record| 
    Meeting.decrement_counter(:users_count, record.meeting.id) 
    } 

end 
22

A partire da Rails3.0.5 e nelle versioni più recenti, si sono ora in grado di impostare la cache in contrasto con il modello di "linker", nel tuo caso sarà:

class MeetingUser < ActiveRecord::Base 
    belongs_to :meeting, :counter_cache => :users_count 
    belongs_to :user, :counter_cache => :meetings_count 
end 

È importante specificare esplicitamente i nomi delle colonne di conteggio, altrimenti le colonne utilizzate verranno impostate per default su meeting_users_count.

+0

Questo ha funzionato per me. Meno codice della soluzione after_create ... – tstyle

+0

Funziona meglio anche per me! Dopo aver creato gli eventi vengono saltati in assegnazione di massa. Questa dovrebbe essere la risposta accettata. –