Progettazione del database, processore incoerenza

4

Mi stavo chiedendo, se ho una tabella che memorizza, diciamo, le transazioni di un utente, quindi quando ho bisogno di recuperare il saldo corrente dell'utente dovrei andare e usare SUM() come SELECT SUM(value) FROM transactions . Ma ciò sembra ridondante nel mondo php + MySQL perché un utente può aggiornare la pagina 3 volte in un secondo se lo desidera e se quell'utente avesse utilizzato il mio servizio per alcuni anni e avesse centinaia di migliaia di transazioni, I ' sto andando a calcolare questo ogni volta che viene richiesta una pagina?

D'altra parte se creo qualche tipo di cache o un'altra tabella chiamata qualcosa come balances dove memorizzerò solo i saldi correnti degli utenti e la aggiornerò con i trigger dalla tabella delle transazioni - sembra molto più razionale e non sembra che sprecherei risorse, tuttavia il mio senso del codice rotto inizia a formicolare. Posso scommettere che alla fine qualcosa andrà storto, alcune transazioni andranno perse o verranno registrate senza influenzare la tabella dei saldi o qualcosa del genere, davvero.

Quale sarebbe l'approccio migliore e perché?

    
posta php_nub_qq 28.04.2016 - 02:27
fonte

2 risposte

6

Dipende da ciò che sei disposto a fare in termini di profitti architettonici / prestazionali. Sembra che tu stia facendo una sorta di event sourcing , che in effetti ha molto senso quando inizi parlare di domini in cui è importante avere audit-trail per esattamente quello che è successo.

Penso che un punto chiave per evitare il "code rot" sia quello di assicurarsi che il percorso del codice per gli eventi di "replaying" sia lo stesso di fare modifiche la prima volta. Esempio approssimativo:

// Don't do this
assert(account.getBalance() == 0);
transactionEvent = account.add(123);
recordInDatabase(transactionEvent);    
assert(account.getBalance() == 123);

// Instead try this
transactionEvent = new TransactionEvent(123, account.getId());
assert(account.getBalance() == 0);
account.apply(transactionEvent); 
assert(account.getBalance() == 123);
recordInDatabase(transactionEvent);

Con il secondo metodo, stai sempre utilizzando apply() per trasformare il tuo oggetto, se gli eventi sono "freschi" o se vengono "riprodotti" dal database. (Avrai ovviamente bisogno di un trattamento speciale per prevenire effetti collaterali esterni come le chiamate al servizio web che si verificano durante i replay, comunque.)

I'm going to calculate this every time a page is requested?

Un'ottimizzazione delle prestazioni da considerare è "istantanee", dove ancora mantieni l'intera sequenza di eventi (es. transazioni) ma registri anche periodicamente cose come "Dopo la transazione # 4155, il saldo era di $ 255,43 ".

Quindi, quando stai cercando di capire il "saldo corrente" dopo la transazione n. 4203, salti direttamente a $ 255,43 e inizia ad aggiungere i valori da tutte le transazioni 4156-4203. Ogni volta che il processo di riassunzione diventa troppo lento, registra una nuova istantanea.

Ancora una volta, le istantanee sono semplicemente ottimizzazioni delle prestazioni: se non ne sono disponibili, il codice dovrebbe comunque essere in grado di ricostruire tutto dalla Transazione n. 1 e ottenere sempre la stessa risposta. È possibile impostare un processo in background offline per ricalcolare la verifica dell'integrità delle istantanee.

On the other hand if I create some kind of cache or another table called something like balances

Questo potrebbe essere considerato un "Modello di lettura" per un'architettura CQRS . Una specie di visualizzazione materializzata SQL , tranne per il fatto che puoi riutilizzare il tuo "reale" "codice / linguaggio dell'applicazione per farlo. Se le tue balances righe contengono informazioni sulla versione (come, ad esempio, l'ultimo ID della transazione che faceva parte del calcolo), puoi anche rilevare quando qualcosa è andato storto e diventa obsoleto.

    
risposta data 28.04.2016 - 03:45
fonte
1

Quando ti serviva solo per gestire le Transazioni, allora era sufficiente una singola tabella Transazioni. Ora è necessario conoscere i riepiloghi a livello di account.

Sì, è possibile calcolarli dinamicamente, ma questo rallenterà progressivamente con l'aumentare del numero di Transazioni da scorrere. Questa non è una decisione sull'esperienza utente. Con quale frequenza un utente desidera esaminare un insieme di transazioni? Quante volte l'Utente vorrà conoscere il suo attuale equilibrio?

... another table called something like balances ... update it with triggers ... seems much more rational and does not look like I would be wasting resources, however my broken code sense starts tingling

Questi saldi sono dati derivati ; puoi ricrearli in qualsiasi momento in modo che anche se i tuoi trigger siano incasinati (e dovresti saperlo molto prima che i tuoi utenti inizino a lamentarsi) puoi comunque recuperare i dati richiesti dalle Transazioni (e poi risolvere i trigger).

Per quanto riguarda il tuo "qualcosa andrà male alla fine" asserzione; si, ma dovrebbe davvero accadere (e essere catturato) in Testing prima che abbia la possibilità di accadere in Production.

    
risposta data 28.04.2016 - 14:23
fonte

Leggi altre domande sui tag