2011-08-24 14 views
5

Questa è più una domanda tecnica "come fare" o "approccio migliore".C# LINQ e calcoli che coinvolgono set di dati di grandi dimensioni

Abbiamo un requisito corrente per recuperare i record dal database, inserirli in un elenco "in memoria" e quindi eseguire una serie di calcoli sui dati, cioè i valori massimi, le medie e alcune statistiche personalizzate più specifiche .

L'inserimento dei dati in un elenco "in memoria" non è un problema poiché utilizziamo NHibernate come ORM e svolge un eccellente lavoro di recupero dei dati dal database. Il consiglio che sto cercando è come dovremmo eseguire al meglio i calcoli sulla lista risultante di dati.

Idealmente mi piacerebbe creare un metodo per ogni statistica, MaximumValue(), AverageValueUnder100(), MoreComplicatedStatistic() ecc ecc. Ovviamente passando le variabili richieste a ciascun metodo e facendogli restituire il risultato. Questo approccio renderebbe il test unitario un gioco da ragazzi e ci fornirà una copertura eccellente.

Si verificherà un problema di prestazioni se eseguiamo una query LINQ per ogni calcolo o dovremmo consolidare il numero di chiamate a ciascun metodo di statistica nel minor numero possibile di query LINQ. Ad esempio, non ha molto senso passare l'elenco di dati a un metodo chiamato AverageValueBelow100 e quindi passare l'intero elenco di dati a un altro metodo AverageValueBelow50 quando potrebbero essere effettivamente eseguiti con una query LINQ.

Come possiamo raggiungere un alto livello di granularità e separazione senza sacrificare le prestazioni?

Qualche consiglio ... la domanda è abbastanza chiara?

+4

L'approccio migliore sarebbe quello di eseguire le query sul database in cui si ha il vantaggio di indici per migliorare le prestazioni –

+0

davvero? quindi, piuttosto che elaborare "in memoria", sarebbe meglio interrogare il database. alcuni dei calcoli sono piuttosto complicati quindi non sono del tutto sicuro che questo sarebbe l'approccio migliore. – Rowen

+1

Molto spesso i database sono più veloci –

risposta

1

A seconda della complessità del calcolo, potrebbe essere meglio farlo nel database. Se è significativo che sia necessario portarlo dentro come oggetti e copiarlo in overhead, potresti voler evitare più iterazioni sul set di risultati. potresti prendere in considerazione l'utilizzo di Aggregate. Vedere http://geekswithblogs.net/malisancube/archive/2009/12/09/demystifying-linq-aggregates.aspx per una discussione se si. Sareste in grado di testare separatamente ciascun aggregato, ma poi (potenzialmente) progettare più aggregati all'interno di una singola iterazione.

1

Non sono d'accordo che è meglio "fare tutto nel database".

Le query di Linq ben scritte si tradurranno in una buona esecuzione di query SQL sul database, che dovrebbero essere sufficientemente buone per quanto riguarda le prestazioni (se non si intende fare roba dwh). Ciò presuppone che si stia utilizzando il provider Linq per NHibernate e non Linq per gli oggetti.

Sembra buono, è possibile cambiarlo facilmente e mantiene la logica aziendale in un unico posto.

Se è troppo lento per le proprie esigenze, è possibile controllare il codice SQL creato e modificare le query di linq, provare a precompilarli e, alla fine, è ancora possibile tornare a scrivere le stored procedure preferite e iniziare per diffondere la tua logica di business ovunque.

Ci sarà un successo nelle prestazioni? Sì, potresti perdere alcuni millisecondi, ma vale il prezzo che devi pagare per separare la tua logica?

+0

Non stavo suggerendo di fare tutto nel database. Stavo solo sconsigliato di ottenere tutti i dati in memoria e quindi eseguire quello che sarebbe effettivamente Linq alle query di oggetti contro quello. –

0

Per rispondere alla domanda "Vorrei creare un metodo per ogni statistica", suggerirei di creare un tipo di classe di statistica.Ecco alcuni pseudo codice per esprimere l'idea:

class Statistician 
{ 
    public bool MustCalculateFIRSTSTATISTIC { get; set; } // Please rename me! 
    public bool MustCalculateSECONDSTATISTIC { get; set; } // Please rename me! 

    public void ProcessObject(object Object) // Replace object and Rename 
    { 
     if (MustCalculateFIRSTSTATISTIC) 
      CalculateFIRSTSTATISTIC(Object); 

     if (MustCalculateFIRSTSTATISTIC) 
      CalculateSECONDSTATISTIC(Object); 
    } 

    public object GetFIRSTSTATISTIC() // Replace object, Rename 
    { /* ... */ } 
    public object GetSECONDSTATISTIC() // Replace object, Rename 
    { /* ... */ } 

    private void CalculateFIRSTSTATISTIC(object Object) // Replace object 
    { /* ... */ } 
    private void CalculateSECONDSTATISTIC(object Object) // Replace object 
    { /* ... */ } 
} 

avrei dovuto fare questo, io probabilmente cercare di rendere le collezioni generiche e sull'uso di delegati, invece di metodi, ma dal momento che non conosco il tuo contesto , Lo lascerò a quello. Nota anche che ho usato solo i membri Object della classe object, ma questo è solo perché non sto suggerendo di usare DataRows, Entities o cosa no; Lo lascerò agli altri che sanno più di me sull'argomento!

Problemi correlati