2011-08-24 38 views
5

Esta es una cuestión más técnica de "cómo hacerlo" o de "mejor enfoque".C# LINQ y cálculos que involucran grandes conjuntos de datos

Tenemos un requerimiento actual para recuperar registros de la base de datos, colocarlos en una lista 'en memoria' y luego realizar una serie de cálculos sobre los datos, es decir, valores máximos, promedios y algunas estadísticas personalizadas más específicas. .

Obtener los datos en una lista 'en la memoria' no es un problema ya que utilizamos NHibernate como nuestro ORM y hace un trabajo excelente al recuperar datos de la base de datos. El consejo que estoy buscando es cómo realizar mejor los cálculos en la lista de datos resultante.

Idealmente me gustaría crear un método para cada estadística, MaximumValue(), AverageValueUnder100(), MoreComplicatedStatistic() etc etc. Por supuesto, pasar las variables requeridas a cada método y hacer que devuelva el resultado. Este enfoque también haría las pruebas unitarias simples y nos proporcionaría una excelente cobertura.

¿Habría un golpe de rendimiento si realizamos una consulta LINQ para cada cálculo o deberíamos consolidar tantas llamadas a cada método de estadística en tan pocas consultas LINQ como sea posible. Por ejemplo, no tiene mucho sentido pasar la lista de datos a un método llamado AverageValueBelow100 y luego pasar toda la lista de datos a otro método, AverageValueBelow50, cuando podrían ser efectivamente realizados con una consulta LINQ.

¿Cómo podemos lograr un alto nivel de granularidad y separación sin sacrificar el rendimiento?

Cualquier consejo ... ¿es la pregunta lo suficientemente clara?

+4

¿El mejor enfoque sería realizar las consultas contra la base de datos donde tiene el beneficio de los índices para mejorar el rendimiento –

+0

realmente? entonces, en lugar de procesar 'en memoria' sería mejor consultar la base de datos. algunos de los cálculos son bastante complicados, así que no estoy del todo seguro de que este sea el mejor enfoque. – Rowen

+1

La mayoría de las bases de datos son más rápidas –

Respuesta

1

Dependiendo de la complejidad del cálculo, puede ser mejor hacerlo en la base de datos. Si es significativamente complejo que necesite incluirlo como objetos e involucrar esa sobrecarga, es posible que desee evitar múltiples iteraciones sobre su conjunto de resultados. es posible que desee considerar el uso de Agregado. Vea http://geekswithblogs.net/malisancube/archive/2009/12/09/demystifying-linq-aggregates.aspx para una discusión si. Podrías probar cada unidad por separado, pero luego (potencialmente) proyectar múltiples agregados en una sola iteración.

1

No estoy de acuerdo en que es mejor "hacerlo todo en la base de datos".

Las consultas Linq bien redactadas darán lugar a buenas consultas SQL ejecutándose contra la base de datos, lo que debería ser lo suficientemente bueno en cuanto al rendimiento (si no va a hacer cosas dwh). Esto supone que está utilizando Linq Provider para NHibernate y no Linq to Objects.

Se ve bien, puede cambiarlo fácilmente y mantiene la lógica de su negocio en un solo lugar.

Si es demasiado lento para sus necesidades, puede verificar el código SQL creado y modificar sus consultas de linq, intentar precompilarlas, y al final puede volver a escribir los procedimientos almacenados preferidos - y comenzar para difundir su lógica de negocios por todo el lugar.

¿Habrá un golpe de rendimiento? Sí, podrías perder algunos milisegundos, pero ¿vale la pena el precio que tienes que pagar para separar tu lógica?

+0

No estaba sugiriendo hacerlo todo en la base de datos. Solo estaba aconsejando no obtener todos los datos en memoria y luego realizar lo que efectivamente sería Linq para las consultas de objetos en contra de eso. –

0

Para responder al problema de "Me gustaría crear un método para cada estadística", le sugiero que cree una especie de clase de estadístico.Aquí hay un código de pseudo para expresar la 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 
    { /* ... */ } 
} 

tendría que hacer esto, yo probablemente tratar de hacer que las colecciones genéricas y uso de los delegados en lugar de métodos, pero ya no sé su contexto , Lo dejo a eso. También tenga en cuenta que solo usé miembros Object de la clase de objeto, pero eso es solo porque no sugiero que use DataRows, Entidades o lo que no; ¡Dejaré eso a las otras personas que saben más que yo sobre el tema!

Cuestiones relacionadas