Entità nidificate e calcolo sulla proprietà dell'entità foglia - approccio SQL o NoSQL


10

Sto lavorando a un progetto di hobby chiamato Menu / Gestione ricette.

Ecco come appaiono le mie entità e le loro relazioni.

A Nutrientha proprietà CodeeValue

An Ingredientha una collezione diNutrients

A Recipeha una raccolta di Ingredientse occasionalmente può avere una raccolta di altrirecipes

A Mealha una collezione di RecipeseIngredients

A Menuha una collezione diMeals

Le relazioni possono essere rappresentate come

Entità e relazioni del menu

In una delle pagine, per un menu selezionato ho bisogno di visualizzare le informazioni sui nutrienti efficaci calcolate in base ai suoi componenti (pasti, ricette, ingredienti e i corrispondenti nutrienti).

A partire da ora sto usando SQL Server per memorizzare i dati e sto navigando nella catena dal mio codice C #, a partire da ogni pasto del menu e quindi aggregando i valori dei nutrienti.

Penso che questo non sia un modo efficace in quanto questo calcolo viene eseguito ogni volta che viene richiesta la pagina e i componenti cambiano di tanto in tanto.

Stavo pensando di avere un servizio in background che mantiene una tabella chiamata MenuNutrients ( {MenuId, NutrientId, Value}) e popolerà / aggiornerà questa tabella con i nutrienti efficaci quando uno qualsiasi dei componenti (Pasto, Ricetta, Ingrediente) cambia.

Sento che un GraphDB sarebbe adatto a questo requisito, ma la mia esposizione a NoSQL è limitata.

Voglio sapere quali sono le soluzioni / approcci alternativi a questo requisito di visualizzazione dei nutrienti di un determinato menu.

Spero che la mia descrizione dello scenario sia chiara.


Di quanti oggetti stiamo parlando? Le prestazioni saranno davvero un problema?
flup

@flup In media un menu può avere 8 pasti, ogni pasto può avere 2 ricette e 2 ingredienti, ogni ricetta può avere 6-8 ingredienti.
Chandu,

Le tue frecce non sono nella direzione sbagliata?
Branko Dimitrijevic,

Hai visto un esempio di Nerd Dinner Entity Framework?
Akash Kava,

Risposte:


8

In base ai requisiti e all'architettura, potrebbero essere disponibili opzioni di miglioramento delle prestazioni:

  • È possibile utilizzare le viste indicizzate (matrializzate) per migliorare le prestazioni di lettura a livello di RDBMS (server SQL).
    Fondamentalmente, tutto ciò che devi fare è:
    creare una vista regolare.
    Crea un indice cluster su quella vista .

  • L'uso di un meccanismo di incassi a livello di applicazione migliorerà le prestazioni.
    Se è possibile e fattibile utilizzare l'incasso, avere una strategia in denaro come l' incasso pigro singleton ti aiuterà.

NoSql:
ci sono molti buoni articoli su Sql vs NoSql, come questo e questo

Le parti mi interessano:

Dove usare NoSql:

Se il tuo DB è 3NF e non fai alcun join (stai solo selezionando un gruppo di tabelle e mettendo insieme tutti gli oggetti, AKA cosa fanno la maggior parte delle persone in un'app Web.

Quando usato, sii pronto a:

  • Finisci per scrivere lavori per fare cose come unire dati da diverse tabelle / raccolte, cosa che un RDBMS farebbe automaticamente per te.
  • Le funzionalità di query con NoSQL sono drasticamente paralizzate. MongoDb potrebbe essere la cosa più vicina a SQL ma è ancora estremamente indietro. Fidati di me. Le query SQL sono super intuitive, flessibili e potenti. Le query NoSql non lo sono.
  • Le query MongoDb possono recuperare dati da una sola raccolta e sfruttare un solo indice. E MongoDb è probabilmente uno dei database NoSQL più flessibili. In molti scenari, ciò significa più viaggi di andata e ritorno al server per trovare record correlati. E poi inizi a de-normalizzare i dati, il che significa lavori in background.
  • Il fatto che non si tratti di un database relazionale significa che non avrete vincoli di chiave esterna (ritenuti da alcuni inadeguati) per garantire la coerenza dei dati. Ti assicuro che questo alla fine creerà incoerenze nei dati nel tuo database. Essere preparato. Molto probabilmente inizierai a scrivere processi o controlli per mantenere coerente il tuo database, che probabilmente non funzionerà meglio che lasciare che RDBMS lo faccia per te.
  • Dimentica le strutture mature come l'ibernazione.

Accanto a decidere di usare o non usare NoSQL, un articolo utile su NoSQL DBMS confronto e l'intenzione di loro potrebbe essere trovato qui come alcuni di essi sono concentrati in alto si legge bassi scrive, la mappa-riducono, HA ...
Avere uno sguardo nella classifica e popolarità di essi , per categoria può essere utile.


Grazie per i dettagli Controllerà i collegamenti e ti risponderà.
Chandu,

3

Infatti non è necessario utilizzare un grafico db, è sufficiente memorizzare i valori richiesti in un livello superiore. È proprio come memorizzare un Ordere OrderItems. non è necessario calcolare il totale ogni volta che un ordine sta per essere visualizzato. Invece devi solo calcolare la somma, l'iva e altre cose e memorizzarle con il tuo Order.

order.Subtotal = order.Items.Sum(item => item.Price);
order.Tax = order.Subtotal * 0.25m; // just a value
order.Total = order.Subtotal + order.Tax;

// fast forward time
var subTotal = order.Items.Sum(item => item.Price);
var tax = subTotal * 0.25m;
var total = subTotal + tax;

if (toal == order.Total) {
   Console.Log("Why the hell I've just re-calculated total?");
}

3

Suggerisco di esaminare il modello di segregazione della responsabilità delle query di comando .

Fondamentalmente invece di creare un singolo modello per leggere e scrivere è possibile creare 2 modelli diversi. Uno ottimizzato per l'aggiornamento e l'altro ottimizzato per le query (lettura, creazione di report, ...). I 2 modelli sono sincronizzati (di solito con eventuale coerenza) utilizzando eventi di dominio (vedi DDD).

Ho iniziato a studiare questo modello alcuni mesi fa e ha davvero cambiato il mio modo di modellare il software. Non è facile perché è un grande cambiamento, soprattutto se utilizzato con altre tecniche come DDD ed Event Sourcing. Ma ne vale la pena.

Ci sono molte risorse disponibili in rete, ricerca di CQRS e DDD (e infine Event Sourcing).

Questo modello può essere utilizzato su SQL e noSql.

Nel tuo caso puoi lanciare un evento ogni volta che i nutrienti vengono cambiati per aggiornare il modello di lettura che è ottimizzato per la lettura. Il modello di lettura può essere ad esempio una vista denormalizzata dei nutrienti del menu (perché non usare un nosql db per una lettura efficiente). Puoi avere più modelli di lettura in base alle query che devi eseguire.

Ci sono alcune implicazioni usando questo approccio ma è molto scalabile ed estensibile.


Questo era l'approccio che stavo contemplando, ma non ero sicuro di come ottenere i dati per il modello di lettura (in pratica un processo dovrebbe procurarmi i dati per il modello di lettura).
Chandu,

Di solito il modello letto viene aggiornato ad ogni modifica. Dovresti implementare l'interfaccia utente con comandi (basati su attività) invece di utilizzare le operazioni crud. In questo modo ogni singolo comando si riflette sul modello letto. Non è necessario eseguire altre query. La progettazione di comandi consente al sistema di catturare il vero intento dell'utente.

2

Dipende molto da come si fa per ottenere inizialmente i menu e i nutrienti. Perché pensi che non sarà efficiente?

Da quello che ho capito, vai nel DB, ottieni il menu, quindi vai di nuovo, ottieni ogni ricetta, poi vai di nuovo a prendere ogni ingrediente e così via. Questo è davvero inefficiente, poiché ci sono molte query e round-trip sul server, che è la principale fonte di ritardi. Questo è noto come il problema SELECT N + 1.

Quello che dovresti fare è recuperare tutti i dati in una singola query, usando JOINs per tutte le tabelle dal menu fino ai nutrienti, in modo che il server DB possa usare tutte le relazioni e gli indici per ottenere i dati tutti in una volta. L'app client C # elabora e visualizza solo il risultato finale. Farlo è molto più efficiente che andare uno per uno.

In generale, utilizzando le tecniche di query appropriate e gli indici giusti per le query critiche, i database relazionali possono funzionare molto bene su grandi tabelle sotto carico.


Grazie, capisco che dipende dai join. Poiché i componenti del menu cambiano di tanto in tanto, non voglio eseguire il calcolo ogni volta che qualcuno accede alla pagina. Voglio invece che un servizio in background esegua il calcolo e posso semplicemente leggerlo da una tabella quando necessario. Il problema con il calcolo è l'identificazione dell'intera catena quando uno dei componenti cambia.
Chandu,

Solo la ricerca di alcune relazioni non comporta alcun calcolo, anche se ci sono 5 o 6 JOINsecondi che non dovrebbero essere un onere sul server (a meno che non stiamo parlando di recuperare centinaia o migliaia di righe), se una corretta indicizzazione è a posto. Anche con set di dati di grandi dimensioni, è sempre possibile creare una vista sull'intero risultato e persino indicizzare la vista per avere il risultato precalcolato, se le prestazioni diventano un problema.

2

Sembra che tu abbia trascorso del tempo a pensare al modo migliore per modellare i dati in modo che possano essere facilmente aggiornati e interrogati. Tuttavia, ora sei nel punto in cui devi fornire l'accesso ai dati. Queste due cose sono preoccupazioni separate.

Si dice che ricaricare la pagina sta causando una nuova query nel database. Si menziona inoltre che il database verrà occasionalmente aggiornato e quando si desidera che tali aggiornamenti vengano visualizzati sulla pagina in modo tempestivo. Il metodo migliore per ridurre il sovraccarico delle query non è di eseguirle. Se esegui sempre le stesse query e ottieni gli stessi risultati, perché non memorizzarle nella cache per un po '? Dovresti essere in grado di implementare un po 'di cache a monte senza modificare il resto del progetto. Consiglierei di leggere sul riposo. Indipendentemente se si implementa il progetto in un rdbms o nosql, i problemi con prestazioni di questo tipo vengono gestiti meglio riducendo il numero di volte che si deve andare nel database. Supponi di avere 100 richieste per la stessa ricetta in 60 secondi. Se si memorizza nella cache per 60 secondi, si accede al database solo una volta, quindi questo è un miglioramento di 100 volte nelle prestazioni. Vedere lo stesso livello di miglioramento passando a nosql richiederà molto più lavoro.

I sistemi di tipo Nosql possono essere un'ottima soluzione quando si hanno enormi quantità di dati o requisiti estremi di velocità di lettura o scrittura. Tuttavia, le prestazioni extra comportano il costo di eliminare elementi come l'integrità referenziale.


1

Sembra che per l'esperimento o lo scopo della conoscenza tu voglia provare Graph-DB ma il tuo esempio è chiaramente un esempio di dati gerarchici in cui possiamo Drill-Down / Up attraverso un nodo. Non sono esperto di Graph / Neo DB, ma vedo che non vi è molta complessità nel modo in cui l'utente / è possibile richiedere dati da questo schema. Vedo che la scelta del design del database / schema dipende molto da come e da quale tipo di dati verranno interrogati. Mentre usi SQLSERVER "HierarchyI" D è la migliore opzione dal mio punto di vista per inserire questi nodi come parte di Tree.


1

Il mio consiglio è di pensare come una macchina e non come un essere umano. Può sembrare ripetitivo, ma che macchine sono bravi. Una cosa che devi chiederti è "devo recuperare ogni oggetto, comunque, per visualizzarlo sulla mia pagina?" Se sì, continua quello che stai facendo, rispetto al recupero dei dati, i cicli della CPU sono trascurabili quando fai matematica semplice.

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.