ACTUALIZACIÓN 3: De acuerdo con este anuncio , esto ha sido abordado por el equipo EF en EF6 alpha 2.
ACTUALIZACIÓN 2: He creado una sugerencia para solucionar este problema. Para votar por él, vaya aquí .
Considere una base de datos SQL con una tabla muy simple.
CREATE TABLE Main (Id INT PRIMARY KEY)
Completo la tabla con 10,000 registros.
WITH Numbers AS
(
SELECT 1 AS Id
UNION ALL
SELECT Id + 1 AS Id FROM Numbers WHERE Id <= 10000
)
INSERT Main (Id)
SELECT Id FROM Numbers
OPTION (MAXRECURSION 0)
Construyo un modelo EF para la tabla y ejecuto la siguiente consulta en LINQPad (estoy usando el modo "C # Statements" para que LINQPad no cree un volcado automáticamente).
var rows =
Main
.ToArray();
El tiempo de ejecución es de ~ 0,07 segundos. Ahora agrego el operador Contiene y vuelvo a ejecutar la consulta.
var ids = Main.Select(a => a.Id).ToArray();
var rows =
Main
.Where (a => ids.Contains(a.Id))
.ToArray();
¡El tiempo de ejecución para este caso es 20,14 segundos (288 veces más lento)!
Al principio sospeché que el T-SQL emitido para la consulta tardaba más en ejecutarse, así que intenté cortarlo y pegarlo desde el panel SQL de LINQPad en SQL Server Management Studio.
SET NOCOUNT ON
SET STATISTICS TIME ON
SELECT
[Extent1].[Id] AS [Id]
FROM [dbo].[Primary] AS [Extent1]
WHERE [Extent1].[Id] IN (1,2,3,4,5,6,7,8,...
Y el resultado fue
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 88 ms.
Luego sospeché que LINQPad estaba causando el problema, pero el rendimiento es el mismo si lo ejecuto en LINQPad o en una aplicación de consola.
Entonces, parece que el problema está en algún lugar dentro de Entity Framework.
¿Estoy haciendo algo mal aquí? Esta es una parte de mi código en la que el tiempo es crítico, entonces, ¿hay algo que pueda hacer para acelerar el rendimiento?
Estoy usando Entity Framework 4.1 y Sql Server 2008 R2.
ACTUALIZACIÓN 1:
En la discusión a continuación, hubo algunas preguntas sobre si el retraso ocurrió mientras EF estaba construyendo la consulta inicial o mientras analizaba los datos que recibió. Para probar esto, ejecuté el siguiente código,
var ids = Main.Select(a => a.Id).ToArray();
var rows =
(ObjectQuery<MainRow>)
Main
.Where (a => ids.Contains(a.Id));
var sql = rows.ToTraceString();
lo que obliga a EF a generar la consulta sin ejecutarla en la base de datos. El resultado fue que este código requirió ~ 20 segundos para ejecutarse, por lo que parece que se toma casi todo el tiempo para construir la consulta inicial.
CompiledQuery al rescate entonces? No tan rápido ... CompiledQuery requiere que los parámetros pasados a la consulta sean tipos fundamentales (int, string, float, etc.). No acepta matrices o IEnumerable, por lo que no puedo usarlo para una lista de ID.
var qry = Main.Where (a => ids.Contains(a.Id)); var rows = qry.ToArray();
ver qué parte de la consulta se está demorando?