2010-03-16 14 views
8

¿Hay alguna diferencia en el rendimiento (asintótica) entre¿Primero() realizará el OrderBy()?

var a = Orders.OrderBy(order => order.Date).First() 

y

var y = Orders.Where(order => order.Date == Orders.Min(x => x.Date)).ToList(); 

es decir, en primer lugar() realizar la OrdenarPor()? Supongo que no. MSDN dice que enumerar la colección a través de foreach och GetEnumerator sí pero la fraseología no excluye otras extensiones.

+1

Como un aparte, y como dijo Guffa, estos dos no son idénticos, la segunda opción puede devolver más de un valor, el primero no puede. –

Respuesta

7

algunas cosas:

  • OrderBy() órdenes de pequeño a grande, por lo que sus dos alternativas devuelven diferentes elementos
  • Where() suele ser lento, por lo que su segunda expresión en realidad no hace ningún cálculo en absoluto - no hasta que se use.
  • En principio, el comportamiento en cuestión depende del proveedor de la consulta. Por ejemplo, es posible que espere que el proveedor de consultas sqq del servidor SQL trate este problema de manera diferente que el proveedor de consultas IEnumerable. Un proveedor de consultas puede elegir que el valor devuelto de "OrderBy" sea lo suficientemente especializado como para llamar First() y reconocer (ya sea en compilación o en tiempo de ejecución) que se ejecuta en un enumerable ordenado y en lugar de ordenar, opta por devolver (primero) elemento mínimo.
  • Específicamente para el proveedor de IEnumerable<T>, OrderBy pasa a devolver un enumerable que completamente tampones y clasifica la entrada cada vez que se recupera el primer elemento - por lo que, en el caso básico común Linq-to-objetos, OrderBy().First() es comparable a OrderBy().ToArray().

Recuerde que linq es solo un grupo de nombres de funciones: cada proveedor puede optar por implementarlos de manera diferente, por lo que lo anterior solo se aplica al proveedor de consultas IEnumerable System.Linq, y no necesariamente a otros.

+0

Ya veo. Me imagino que linq2sql podría optimizar el sql para la primera declaración. Si no, sql-server podría optimizar la interpretación. Si no, entonces pronto lo sabré. ¿Derecha? – Martin

+0

Realmente intentarlo es una buena manera de descubrirlo de inmediato :-) - pero claro, eso suena bien para mí. –

0

No es así. DICHO ESO, naturalmente, el orden se ejecutará en el momento en que alguien intente obtener realmente el primer elemento.

Pero como ha dicho, las condiciones se pueden definir con mayor detalle. Como tal, no, no se ejecuta en ese momento.

+0

Mientras sea técnicamente correcto, creo que está dando una impresión equivocada al OP. – Blindy

+1

Pero First() en realidad está obteniendo el primer elemento, así que estoy bastante seguro de que la primera fila ejecutará de hecho el OrderBy – CodingInsomnia

+0

Si bien es cierto, no es una diferencia. El tiempo en la segunda consulta no se ejecutará hasta que alguien realmente obtenga el resultado. – Guffa

5

First devolverá la primera entrada del IEnumerable que se le haya pasado. Dado que el IEnumerable pasó a First es el resultado de OrderBy, su pregunta se puede reformular como "¿Funciona el OrderBy?" Y sí.

First no se puede diferir la ejecución de OrderBy porque devuelve el resultado de inmediato. Por ejemplo:

 var numbers = new int[] { 9, 3, 4, 6, 7 }; 

     var num = numbers.First(); 
     Console.WriteLine(num); 

     num = numbers.OrderBy(i => i).First(); 
     Console.WriteLine(num); 

     Console.ReadLine(); 
+0

Lo anterior ya no es cierto para .NET 4.7.1. OrderBy devuelve un OrderedEnumerator, pero en realidad no ha ordenado la lista a la devolución. Cuando llama a First(), solo tiene que mirar a través de los objetos, y llegar al elemento que sería primero, y eso es lo que hace ahora, sin molestarse en ordenar la lista. También parece ser O (n) si la lista ha sido ordenada. Ver asignaciones https://github.com/dotnet/corefx/blob/ed0ee133ac49cee86f10ca4692b1d72e337bc012/src/System.Linq/src/System/Linq/OrderedEnumerable.cs –

6

El método First realizará la OrderBy (es decir, dado que el método First se ejecuta por supuesto). Cuando el método First extrae el primer elemento del resultado del OrderBy, deberá ordenar todos los elementos para determinar cuál es el primero.

Dependiendo de dónde y cómo se ejecute la consulta (es decir, si el motor de consulta no puede optimizar a su alrededor), la segunda consulta puede funcionar bastante mal. Si Orders.Max se evalúa una vez para cada elemento en Orders, se convierte en una operación O (n * n), lo cual es bastante malo.

También existe una diferencia funcional, la segunda consulta puede devolver más de un elemento si hay fechas duplicadas.

+0

Añadido para mayor claridad. Se ejecutará ahora, ¿no? – Martin

+0

@Martin: El primero se ejecutará pero no el segundo. El primero obtendrá el primer elemento y lo asignará a la variable, pero el segundo creará una expresión que puede devolver el resultado. La expresión no se ejecutará hasta que lea el resultado, por ejemplo: 'List earlyOnes = y.ToList();'. – Guffa

+0

Añadido tolist. :) – Martin

Cuestiones relacionadas