Almacenar vs calcular valores agregados


96

¿Existen pautas o reglas generales para determinar cuándo almacenar valores agregados y cuándo calcularlos sobre la marcha?

Por ejemplo, supongamos que tengo widgets que los usuarios pueden calificar (ver el esquema a continuación). Cada vez que visualizo un widget, puedo calcular la calificación promedio de los usuarios de la Ratingstabla. Alternativamente, podría almacenar la calificación promedio en la Widgetmesa. Esto me evitaría tener que calcular la calificación cada vez que visualizo el widget, pero luego tendría que volver a calcular la calificación promedio cada vez que un usuario calificara un widget.

Ratings       Widgets
---------     -------
widget_id     widget_id
user_id       name              
rating        avg_rating  <--- The column in question

Respuestas:


58

Depende. El cálculo previo de los valores agregados coloca una carga mayor en las escrituras, derivarlas hace que las lecturas sean más difíciles

Si accede con frecuencia a un valor derivado, el cálculo previo es un paso de desnormalización válido. Sin embargo, en este caso, recomiendo usar una Vista Materializada (una vista, escrita en el disco, vinculada por disparador a las tablas principales). La vista materializada está diseñada para almacenar datos frecuentes pero tediosos de derivar, y es útil para un gran número de escrituras y bajos números de lecturas.

En un escenario de alta escritura y alta lectura, considere tener una tarea en segundo plano que imite los efectos de una vista materializada, pero en menos de tiempo real. Esto presentará un promedio "suficientemente bueno" al tiempo que conserva el rendimiento de escritura y lectura.

En ninguna circunstancia, debe tratar la columna derivada como una columna "normal": asegúrese de que los datos presentados en la "vista" de Widgets estén presentes en otra parte de la tabla, de modo que toda la tupla pueda derivarse por cualquier proceso que coloque. Esta pregunta también es fuertemente específica de la base de datos (y la versión de la base de datos), por lo que recomiendo probar el rendimiento del agregado (con índices apropiados) contra un conjunto de datos de tamaño normal y la vista materializada.


Esta discusión me pareció muy útil con respecto a las vistas materializadas. Está diseñado para Oracle, pero se puede entender genéricamente. Para aquellos como yo que vinimos de un fondo MySQL, una vista MySQL es diferente de una vista Materializada, es virtual y no se almacena en el disco (como se mencionó en el enlace que di).
Siddhartha

¡votado! estaba a punto de hacer la pregunta exacta, necesito almacenar indicadores como SMA, EMA, WMA, RSI, etc. e implican un gran cálculo, estaba haciendo una tabla que estaba actualizando manualmente hasta ahora, estos indicadores cambian 100% cada vez con entran datos nuevos, cuál es una buena estrategia para mantenerlos, sé que las vistas destrozarán por completo la base de datos si todos comienzan a consultar las vistas de izquierda a derecha
PirateApp

11

Con qué frecuencia necesita calcular / mostrar los valores relativos a la frecuencia con la que se cambian / actualizan los números subyacentes.

Entonces, si tiene un sitio web con 10k visitas diarias que muestra un valor que solo cambiará una vez por hora, lo calcularía cuando cambien los valores subyacentes (podría ser un desencadenante de la base de datos, lo que sea).

Si tiene una herramienta para ver las estadísticas, donde las estadísticas cambian por segundo, pero solo tres personas tienen acceso, y solo lo miran un par de veces al día, es más probable que calcule sobre la marcha. (a menos que, tome un par de minutos calcular que haber tenido datos obsoletos en primer lugar no es gran cosa ... y mi jefe me dice que genere la cosa desde cron cada hora, por lo que no tiene esperar cuando quiera mirarlo.)


cada 15 minutos, 10 métricas que cambian al 100% con 1000 filas por métrica
PirateApp

1
@PirateApp y ¿cuántas veces se ve en una ventana promedio de 15 minutos? Lo que también puede hacer es generarlo a la primera solicitud en una ventana de 15 minutos y luego almacenarlo en caché para las personas que siguen presionando la recarga una y otra vez
Joe

estará en un sitio web, así que supongo que al menos 10000 personas lo verán para empezar, el sitio no está en funcionamiento, así que no tengo datos reales sobre el comportamiento del usuario
PirateApp

1
El problema es cuántas solicitudes en relación con la frecuencia con que cambian. Entonces, si pregeneras algo que se verá 10,000 veces antes de que los datos subyacentes cambien, entonces sí, pregeneralo. Si solo se ve una vez, o menos de una vez (porque los datos cambian muy rápidamente o porque la página rara vez se mira), entonces no lo hace.
Joe

4

Utilice la tabla StaleWidgets como una cola de widgets "no válidos" (para ser recalculados). Utilice otra tarea de subproceso (asíncrono) que pueda volver a calcular estos valores. El período o momento de recálculos depende de los requisitos del sistema:

  • solo en lectura,
  • a finales de mes
  • para algún usuario al comienzo del día
  • ...

1
¿Cómo entran entonces en la cola rancia?
jcolebrand

2
@jcolebrand ..en el momento de insertar / eliminar la calificación (tabla de calificaciones) para algún widget. En este momento, el valor promedio en la tabla Widgets se está volviendo inválido, por lo que debemos insertar en el registro StaleWidgets de la tabla que solo tiene una columna: widget_id. Utilice el activador o el proceso almacenado que inserte el registro en la tabla de calificaciones o su variante, por supuesto.
garik

2

Sugeriría que calcule sobre la marcha si el cálculo no es demasiado engorroso y en el caso de que tenga cálculos complejos y actualizaciones frecuentes, pero no esa lectura de frecuencia que puede almacenar datos calculados y tener una columna adicional (bool) que almacenará si se requiere un recálculo o no . por ejemplo, establezca esta columna en verdadero siempre que se deba realizar el recálculo, pero no realice el recálculo y cuando realice el recálculo, establezca esta columna como falsa (esto representará que el valor calculado es el último y no está obsoleto).

De esta manera, no tiene que volver a calcular cada vez, solo calculará cuando tenga que leer y el valor de la columna de recálculo sea verdadero. De esta manera, ahorrará muchos recálculos.


2

Para el caso en particular, existe una solución diferente en la que no tiene que agregar todas las calificaciones y dividirlas por el total para encontrar el promedio. En cambio, puede tener otro campo que contenga el total de las revisiones, por lo tanto, cada vez que agrega una calificación, calcula el nuevo promedio usando (avg_rating × total + new_rating) / total, esto es mucho más rápido que el agregado y reduce las lecturas del disco ya que no tiene que acceder a todos los valores de calificación. Soluciones similares podrían aplicarse a otros casos.

La desventaja de esto es que no es una transacción ácida, por lo que puede terminar con una calificación desactualizada. Pero aún así puede resolverlo utilizando desencadenantes en la base de datos. El otro problema es que la base de datos ya no está normalizada, pero no tenga miedo de desnormalizar los datos a cambio del rendimiento.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.