2011-09-12 11 views
6

Tome la siguiente consulta LINQ como ejemplo. Por favor, no comenten el código en sí, ya que lo he escrito para ayudar con esta pregunta.Gran consulta de agrupamiento LINQ, lo que está sucediendo detrás de las escenas

La siguiente consulta LINQ utiliza un 'grupo por' y calcula la información de resumen. Como puede ver, hay numerosos cálculos que se están realizando sobre los datos pero cuán eficiente es LINQ detrás de las escenas.

var NinjasGrouped = (from ninja in Ninjas 
    group pos by new { pos.NinjaClan, pos.NinjaRank } 
    into con 
    select new NinjaGroupSummary 
    { 
     NinjaClan = con.Key.NinjaClan, 
     NinjaRank = con.Key.NinjaRank, 
     NumberOfShoes = con.Sum(x => x.Shoes), 
     MaxNinjaAge = con.Max(x => x.NinjaAge), 
     MinNinjaAge = con.Min(x => x.NinjaAge), 
     ComplicatedCalculation = con.Sum(x => x.NinjaGrade) != 0 
     ? con.Sum(x => x.NinjaRedBloodCellCount)/con.Sum(x => x.NinjaDoctorVisits) 
     : 0, 
    ListOfNinjas = con.ToList() 
    }).ToList(); 
  1. ¿Cuántas veces se presenta la lista de los 'ninjas' se repiten a lo largo con el fin de calcular cada uno de los valores?
  2. ¿Sería más rápido emplear un bucle foreach para acelerar la ejecución de dicha consulta?
  3. Añadir '.AsParallel()' después de Ninjas dará como resultado alguna mejora en el rendimiento?
  4. ¿Existe alguna forma mejor de calcular la información veraniega para List?

Cualquier consejo es apreciado ya que usamos este tipo de código en todo nuestro software y realmente me gustaría obtener una mejor comprensión de lo que LINQ está haciendo debajo del capó (por así decirlo). Tal vez hay una mejor manera?

+1

+1 para los ninjas. –

+0

Es importante saber si 'Ninjas' es un' IEnumerable' o un 'IQueryable'. Si es anterior, se enumeraría exactamente una vez. Si es posterior, no hay enumeración para hablar; la consulta se compila en, por ejemplo, SQL directamente; el DBMS realiza la agrupación y lo único que se enumera en C# es el conjunto de resultados. –

+0

'Ninjas' es una lista en memoria, IEnumerable. – Belinda

Respuesta

6

Asumiendo que esto es un LINQ a objetos de consulta:

  • Ninjas es solamente repiten a lo largo de una vez; los grupos se crean en listas concretas internas, que luego se repiten varias veces (una por agregación).
  • El uso de un bucle foreach casi no aceleraría las cosas; podría beneficiarse un poco más de la coherencia del caché (ya que cada vez que itere sobre un grupo probablemente tendrá que recuperar datos de un caché de nivel superior o memoria principal)) pero dudo mucho de que sea significativo. El aumento del dolor en la implementación probablemente sería ser significativa aunque :)
  • Usando AsParallel poder acelerar las cosas - se ve muy fácilmente paralelizable. Vale la pena intentarlo ...
  • No hay una manera mucho mejor para LINQ to Objects, para ser honesto. Sería bueno poder realizar la agregación mientras se está agrupando, y las Extensiones reactivas le permitirían hacer algo así, pero por el momento este es probablemente el enfoque más simple.

Es posible que desee echar un vistazo a la GroupBy post in my Edulinq blog series para más detalles sobre una posible aplicación.

+1

Gracias Jon, de hecho esta es una consulta de LINQ to Objects. ¿Puede ampliar su comentario? "El uso de un bucle foreach casi seguro no aceleraría las cosas", no veo cómo esto es cierto si las listas concretas internas se repiten (potencialmente) en numerosas ocasiones. – Belinda

+0

@Belinda: Bueno, está procesando la misma cantidad de datos, simplemente estaría haciendo un seguimiento de las cosas de forma ligeramente diferente. Supongo que te beneficiarías un poco de la coherencia de la memoria caché, pero dudo mucho de que sea significativa. Editará para aclararlo. –

+0

@JonSkeet ¿No habría nada más que un ciclo sobre 'con' para acelerar las cosas, ya que sería capaz de calcular todos los valores agregados de una vez? (Ahora, cada agregado necesita iterar 'con' por sí mismo) – Magnus

Cuestiones relacionadas