2011-01-15 7 views
5

¿Cómo puedo optimizar mis consultas SQL, hacer caso omiso de este tipo de situaciones:counter_cache optimización has_many_through sql, reducir el número de consultas SQL

Meeting.find (5) .users.size => SELECT COUNT (*) dE DONDE ... ...

User.find (123) .meetings.size => SELECT COUNT (*) Desde ... DONDE ...

no tengo ni idea de cómo utilizar counter_cache aquí.

Aquí es mi modelo de relación:

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 

¿Cuáles son las soluciones más óptimas?

¿Y cómo implementar counter_cache aquí?

+0

¿Hay algo aquí que le impida hacer algo como MeetingUser.where (: meeting_id => 5,: user_id => 123) .size para ambas situaciones? Al menos en ese caso, podrá aprovechar el almacenamiento en caché de consultas SQL. La implementación predeterminada de counter_cache no te ayudará en este tipo de situación. – jmcnevin

+1

Creo que estás equivocado. counter_cache ayudará aquí. Por ejemplo, cuando presenta una lista de usuarios en la vista, y mostrará en cada línea cuántas reuniones tiene cada usuario? Con counter_cache esta será una consulta SQL, sin ella será 1 + n * Users.size – astropanic

Respuesta

1

Hasta donde yo sé, no puede usar counter_cache con through asociaciones, es por eso que debe incrementarlo manualmente.

Por ejemplo (no probado):

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 partir de Rails3.0.5 y en las últimas versiones, que ahora son capaces de establecer caché en contra del modelo de "enlazador", en su caso, será:

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

Es importante especificar explícitamente los nombres de las columnas de recuento, de lo contrario, las columnas utilizadas tendrán como valor predeterminado meeting_users_count.

+0

Esto funcionó para mí. Menos código que la solución after_create ... – tstyle

+0

¡Funciona mejor para mí también! Después de crear eventos se omiten en la asignación masiva. Esta debería ser la respuesta aceptada. –