5

Estoy usando Rails y MySQL, y tengo una pregunta de eficiencia basada en el conteo de filas.¿Está el almacenamiento de recuentos de registros de bases de datos redundantes?

Tengo un modelo Project que has_many :donations.

Quiero contar el número de donantes únicos para un proyecto.

Está teniendo un campo en la tabla projects llamado num_donors, y aumentarlo cuando se crea un nuevo donante, ¿es una buena idea?

O algo así como @num_donors = Donor.count(:select => 'DISTINCT user_id') va a ser similar o lo mismo en términos de eficiencia gracias a la optimización de la base de datos? ¿Esto me requerirá crear índices para user_id y cualquier otro campo que quiera contar?

¿Tiene la misma respuesta para sumar la cantidad total donada?

Respuesta

10

Para responder la pregunta del título. Sí, es redundante, pero si debe hacerlo depende de su situación.

A menos que tenga problemas conocidos de rendimiento, calcule los recuentos y totales sobre la marcha en su aplicación y no los almacene. Es decir, no almacene valores calculados a menos que no tenga otra opción.

En la mayoría de las situaciones, no tendrá que recurrir a esto y no debería hacerlo.

Si debe almacenar los valores calculados, haga lo siguiente:

  • no lo mantenga actualizada mediante el incremento de la misma. Vuelva a calcular el recuento/total de todos los datos cada vez que lo actualice.
  • Si no tiene muchas actualizaciones, ponga el código en un activador de actualización en mantenga el recuento/totales actualizados.
  • El problema con la redundancia en las bases de datos es que cuando los números no coinciden, no está seguro de cuál es autorizado. Agregue a la documentación una nota de que los datos fuente son la fuente autorizada si no están de acuerdo y pueden sobrescribirse.
7

Si bien depende del tamaño de su base de datos, estos son los tipos de operaciones en los que se especializan las bases de datos, por lo que deben ser rápidos. Probablemente sea un caso de optimización prematura aquí; debe comenzar por no almacenar los totales, por lo tanto, hacerlo más simple, y optimizarlo más adelante si es necesario.

4

respuestas JohnFx de Peter y son sólidos, lo que estás proponiendo es la denormalization de tu base de datos, lo que puede mejorar el rendimiento de lectura, pero en detrimento de escrituras, mientras que, además, poniendo la responsabilidad en el desarrollador (o Clevers DBMS adicionales) para evitar inconsistencias dentro de su conjunto de datos.

ActiveRecord tiene algunas funciones integradas para administrar automáticamente los recuentos en las relaciones has_many. Mira esto Railscast on counter caches.

5

Recuerde la máxima "Un hombre con un reloj siempre sabe la hora. Un hombre con dos relojes nunca está seguro." Solo almacenaría el número derivado si:

Problemas de rendimiento le impiden obtener los números derivados cuando los necesita (lo que no debería ser un problema en este caso, ya que la respuesta es probable que esté disponible en los índices)

o

usted tiene razones para creer que usted está perdiendo registros de la tabla principal a través error del programador o la acción del usuario deliberada o accidental. En ese caso, puede utilizar su número derivada para auditar el número actualmente calculada

+0

Me encanta la máxima: no la había escuchado antes. Lo tendré en cuenta :) – nfm

3

¿Lo sabes? que una simple bandera hace la magia de ActiveRecord?

class ThingOwner 

# it has a column like 
# t.integer things_count, :default => 0 

has_many :things, :counter_cache => true 

end 

En cuanto a la pregunta - sí, seguro que es redundante, me gustaría añadir un contador tal si y solamente si la cuota de tiempo things.count 's es demasiado grande.

De lo contrario, es una optimización prematura.

Cuestiones relacionadas