Memorizzazione vs calcolo di valori aggregati


96

Esistono linee guida o regole empiriche per determinare quando memorizzare valori aggregati e quando calcolarli al volo?

Ad esempio, supponiamo che io abbia dei widget che gli utenti possono valutare (vedi schema sotto). Ogni volta che visualizzo un widget potrei calcolare la valutazione media degli utenti dalla Ratingstabella. In alternativa, potrei memorizzare la valutazione media sul Widgettavolo. Questo mi eviterebbe di dover calcolare la valutazione ogni volta che visualizzo il widget, ma poi dovrei ricalcolare la valutazione media ogni volta che un utente ha valutato un widget.

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

Risposte:


58

Dipende. Il pre-calcolo dei valori aggregati comporta un carico maggiore sulle scritture, derivandole rende le letture più difficili

Se si accede frequentemente a un valore derivato, il pre-calcolo è un passaggio di de-normalizzazione valido. Tuttavia, in questo caso, raccomando di utilizzare una vista materializzata (una vista, scritta su disco, collegata tramite trigger alle tabelle padre). La vista materializzata è progettata per archiviare i dati più frequenti ma noiosi da derivare ed è utile per un numero elevato di scritture e un numero basso di letture.

In uno scenario ad alta scrittura e ad alta lettura, considera di avere un'attività in background che imita gli effetti di una vista materializzata, ma in tempo non reale. Ciò presenterà una media "abbastanza buona" preservando le prestazioni di scrittura e lettura.

In nessun caso, dovresti trattare la colonna derivata come una colonna "normale": assicurati che i dati presentati nella "vista" dei Widget siano presenti altrove nella tabella, in modo che l'intera tupla possa essere derivata da qualunque processo tu faccia. Questa domanda è anche fortemente specifica per il database (e la versione del database), quindi raccomando il test delle prestazioni dell'aggregato (con indici appropriati) rispetto a un set di dati di dimensioni normali e alla vista materializzata.


Ho trovato questa discussione molto utile per quanto riguarda le opinioni materializzate. È su misura per Oracle ma può essere compreso genericamente. Per quelli come me che provengono da uno sfondo MySQL, una vista MySQL è diversa da una vista materializzata, è virtuale e non memorizza su disco (come detto nel link che ho dato).
Siddhartha,

upvoted! Stavo per fare la domanda esatta, ho bisogno di memorizzare indicatori come SMA, EMA, WMA, RSI ecc. e comportano un calcolo pesante, stavo preparando una tabella che stavo aggiornando manualmente finora, questi indicatori cambiano al 100% ogni volta con nuovi dati in arrivo, qual è una buona strategia per mantenerli, so che le viste
distruggeranno

11

Con quale frequenza è necessario calcolare / visualizzare i valori relativi alla frequenza con cui i numeri sottostanti vengono modificati / aggiornati.

Quindi, se hai un sito web con 10k hit giornalieri che mostrano un valore che cambierà solo una volta all'ora, lo calcolerei quando cambiano i valori sottostanti (potrebbe essere un trigger di database, qualunque cosa).

Se hai uno strumento per andare a vedere le statistiche, dove le statistiche cambiano di secondo in secondo luogo, ma solo tre persone hanno accesso e lo guardano solo un paio di volte al giorno, avrei più probabilità di calcolare al volo. (a meno che, non ci voglia un paio di minuti per calcolare che avere dati obsoleti in primo luogo non è un grosso problema ... e il mio capo mi dice di generare l'oggetto da cron ogni ora, quindi non ha aspettare quando vuole guardarlo.)


ogni 15 minuti, 10 metriche che cambiano del 100% con 1000 righe per metrica
PirateApp

1
@PirateApp e quante volte viene visualizzato in una finestra media di 15 minuti? Quello che puoi anche fare è generarlo alla prima richiesta in una finestra di 15 minuti e poi memorizzarlo nella cache per le persone che continuano a colpire ripetutamente ricarica
Joe

sarà su un sito Web, quindi suppongo che almeno 10000 persone lo vedranno per cominciare, il sito non è live quindi non hai dati reali sul comportamento degli utenti
PirateApp,

1
Il problema è quante richieste relative alla frequenza con cui cambia. Quindi, se pre-generi qualcosa che verrà visto 10.000 volte prima che i dati sottostanti cambino, allora sì, pre-generalo. Se viene visualizzato solo una volta o meno di una volta (perché i dati cambiano così rapidamente o perché la pagina viene consultata raramente), allora non lo fai.
Joe,

4

Utilizzare la tabella StaleWidgets come una coda di widget "non validi" (da ricalcolare). Utilizzare altre attività di thread (asincrone) che possono ricalcolare questi valori. Il periodo o il momento dei ricalcoli dipende dai requisiti di sistema:

  • appena letto,
  • alla fine del mese,
  • per alcuni utenti all'inizio della giornata
  • ...

1
Come entrano quindi nella coda stantia?
jcolebrand

2
@jcolebrand .. al momento dell'inserimento / eliminazione della valutazione (tabella delle valutazioni) per alcuni widget. In questo momento il valore medio nella tabella Widget non è più valido, quindi dobbiamo inserire nella tabella il record StaleWidgets che ha solo una colonna - widget_id. Usa il trigger o il proc memorizzato che inserisce il record nella tabella delle valutazioni o nella tua variante, ovviamente.
Garik,

2

Suggerirei di eseguire il calating al volo se la calulation non è troppo ingombrante e nel caso in cui tu abbia calcutaion complessi e aggiornamenti frequenti ma non quella lettura frequente di quella che puoi memorizzare i dati calcolati e avere una colonna aggiuntiva (bool) che memorizzerà se il ricalcolo è necessario o meno . ad esempio, impostare questa colonna su true ogni volta che si dovrebbe eseguire il ricalcolo ma non eseguire il ricalcolo e quando si esegue il ricalcolo impostare questa colonna come falsa (ciò rappresenterà il valore calcolato è più recente e non obsoleto).

In questo modo non è necessario ricalcolare ogni volta, si calcolerà solo quando è necessario leggere e il valore della colonna di ricalcolo è vero. In questo modo risparmierai molti ricalcoli.


2

Per il caso in particolare esiste una soluzione diversa in cui non è necessario aggiungere tutte le valutazioni e dividerle per il totale per trovare la media. Invece puoi avere un altro campo che contiene il totale delle recensioni, quindi ogni volta che aggiungi una valutazione calcoli la nuova media usando (avg_rating × total + new_rating) / total, questo è molto più veloce dell'aggregazione e riduce le letture del disco poiché non è necessario accedere a tutti i valori di valutazione. Soluzioni simili potrebbero applicarsi ad altri casi.

Il rovescio della medaglia di questo è che non è una transazione acida, quindi potresti finire con un rating obsoleto. Ma puoi ancora risolverlo usando i trigger nel database. L'altro problema è che il database non è più normalizzato, ma non abbiate paura di denormalizzare i dati in cambio delle prestazioni.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.