2010-11-08 18 views
10

La mia domanda riguarda la denormalizzazione. In un database, quando è necessario archiviare i dati derivati ​​nella propria colonna piuttosto che calcolarlo ogni volta che è necessario?In un database, quando è necessario memorizzare i dati derivati?

Ad esempio, supponiamo di avere utenti che ottengono gli Upvotes per le loro domande. Visualizza la reputazione di un utente sul suo profilo. Quando un utente è upvoted, dovrebbe si incrementa la loro reputazione, o si dovrebbe calcolare quando si recupera il loro profilo:

SELECT User.id, COUNT(*) AS reputation FROM User 
LEFT JOIN Question 
    ON Question.User_id = User.id 
LEFT JOIN Upvote 
    ON Upvote.Question_id = Question.id 
GROUP BY User.id 

Come intensivo del processore fa la query per ottenere la reputazione di un utente deve essere prima che varrebbe la pena di tenerne traccia in modo incrementale con la sua colonna?

Per continuare il nostro esempio, supponiamo che un Upvote abbia un peso che dipende dal numero di Upvotes (non da quanta reputazione) dell'utente che lo ha lanciato. La query per recuperare la loro reputazione esplode all'improvviso:

SELECT 
    User.id AS User_id, 
    SUM(UpvoteWeight.weight) AS reputation 
FROM User 
LEFT JOIN Question 
    ON User.id = Question.User_id 
LEFT JOIN (
    SELECT 
    Upvote.Question_id, 
    COUNT(Upvote2.id)+1 AS weight 
    FROM Upvote 
    LEFT JOIN User 
    ON Upvote.User_id = User.id 
    LEFT JOIN Question 
    ON User.id = Question.User_id 
    LEFT JOIN Upvote AS Upvote2 
    ON 
     Question.id = Upvote2.Question_id 
     AND Upvote2.date < Upvote.date 
    GROUP BY Upvote.id 
) AS UpvoteWeight ON Question.id = UpvoteWeight.Question_id 
GROUP BY User.id 

Questo è lontano dalla proporzione con la difficoltà di una soluzione incrementale. Quando vale la normalizzazione, e quando i benefici della normalizzazione perdono i benefici della denormalizzazione (in questo caso, difficoltà e/o rendimento della query)?

risposta

4

Quanto deve essere intensiva la query per ottenere la reputazione di un utente prima che valga la pena tenerne traccia in modo incrementale con la propria colonna?

Ci sono davvero due domande in questo senso: (1) Questo cambiamento migliorerà la performance e (2) Il miglioramento delle prestazioni sarà valso lo sforzo?


Per quanto riguarda il miglioramento delle prestazioni, questa è fondamentalmente un'analisi standard di pros/cons.

I vantaggi di normalizzazione sono essenzialmente due:

integrità
  • facile dati

  • Nessun problema con ricalcolo (ad esempio, se i dati contenuti cambiano, la colonna derivata deve essere ri -calcolato).

Se si copre l'integrità dei dati con una soluzione robusta attuata (ad esempio grilletto, Sstored-proc-solo le modifiche di dati con le permanenti tabella di cambiamento diretta revocati, ecc ...), allora questo diventa un semplice calcolo di se il costo di verificare se la modifica dei dati di origine garantisce il ri-calcolo dei dati derivati ​​vs.ricalcolare i dati derivati ​​ogni volta. (NOTA: Un altro approccio per mantenere l'integrità dei dati è di forzare il ricalcolo dei dati derivati ​​in base alla pianificazione, dove tali dati possono permettersi di essere inaccurati con una certa tolleranza temporale. StackExchange adotta questo approccio con alcuni dei suoi numeri).

In uno scenario tipico (molti più recuperi di dati e molto meno modifiche ai dati sottostanti) la matematica ovviamente distorce in favore di mantenere i dati derivati ​​de-normalizzati nella tabella.

In alcuni rari casi in cui i dati sottostanti cambiano MOLTO spesso, tuttavia, i dati derivati ​​non vengono recuperati così spesso, facendo ciò potrebbe essere dannoso.


Ora, siamo sulla questione molto più importante: Sarà il miglioramento delle prestazioni valere lo sforzo?

Si prega di notare che, come con tutte le ottimizzazioni, la più grande domanda è "è l'ottimizzazione anche la pena a tutti?", E come tale è soggetto a due considerazioni principali:

  1. misura esatta differenza di prestazioni e generalmente profilazione.

  2. Contesto di questa ottimizzazione specifica nel quadro generale del sistema.

E.g. se la differenza nella query performace - che come sempre deve essere misurata prima dell'ottimizzazione - è del 2% tra i dati derivati ​​memorizzati nella cache e quelli calcolati, la complessità aggiuntiva del sistema nell'implementazione della colonna della reputazione potrebbe non valerne la pena. Ma quale sia la soglia della cura rispetto a non preoccuparsi del miglioramento marginale dipende dal quadro generale della tua app. Se è possibile adottare misure per migliorare il rendimento delle query del 10% in un posto diverso, concentrarsi su quello contro il 2%. Se sei Google e un ulteriore 2% delle prestazioni delle query comporta un costo di 2 miliardi di dollari in hardware aggiuntivo per sostenerlo, deve comunque essere ottimizzato.

1

Non esiste una risposta chiara perché dipende da molti fattori come il volume del sito e la frequenza con cui si visualizza la reputazione (cioè solo sulla pagina del proprio profilo o accanto a OGNI istanza del nome utente, ovunque). L'unica vera risposta è "quando diventa troppo lento"; in altre parole, probabilmente avresti bisogno di testare entrambi gli scenari e ottenere alcune statistiche perfromance reali.

Personalmente vorrei denormalizzare in questa particolare situazione e avere un trigger di inserimento sulla tabella di upvote o una query di aggiornamento periodico che aggiorna la colonna di reputazione denomalizzata. Sarebbe davvero essere la fine del mondo è il rappresentante di qualcuno ha detto "204" invece di "205" fino a quando la pagina si aggiorna?

0

Volevo solo gettare un'altra angolazione sulla preoccupazione dell'integrità dei dati che DVK ha trattato così bene nella risposta sopra. Pensa se altri sistemi potrebbero aver bisogno di accedere/calcolare i dati derivati ​​- anche qualcosa di semplice come un sistema di reporting. Se altri sistemi devono utilizzare il valore derivato o aggiornare il valore di upvote, è possibile che vengano fornite ulteriori considerazioni su come riutilizzare il codice di calcolo o su come garantire che il valore derivato sia costantemente aggiornato indipendentemente dal sistema che modifica l'uptote.

Problemi correlati