Por que o operador Contains () prejudica tanto o desempenho do Entity Framewor

UPDATE 3: de acordo comeste anúncio, isso foi abordado pela equipe EF no EF6 alfa 2.

UPDATE 2: criei uma sugestão para corrigir esse problema. Para votar,go aqui.

onsidere um banco de dados SQL com uma tabela muito simple

CREATE TABLE Main (Id INT PRIMARY KEY)

Povo a tabela com 10.000 registro

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)

Criei um modelo EF para a tabela e execute a seguinte consulta no LINQPad (estou usando o modo "C # Statements" para que o LINQPad não crie um despejo automaticamente

var rows = 
  Main
  .ToArray();

tempo de execução é de ~ 0,07 segundos. Agora, adiciono o operador Contains e execute novamente a consult

var ids = Main.Select(a => a.Id).ToArray();
var rows = 
  Main
  .Where (a => ids.Contains(a.Id))
  .ToArray();

O tempo de execução para este caso é 20,14 segundos (288 vezes mais lento)!

No começo, eu suspeitava que o T-SQL emitido para a consulta estava demorando mais para ser executado, então tentei recortá-lo e colá-lo do painel SQL do LINQPad no SQL Server Management Studi

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,...

E o resultado foi

SQL Server Execution Times:
  CPU time = 0 ms,  elapsed time = 88 ms.

Próximo Suspeitei que o LINQPad estivesse causando o problema, mas o desempenho é o mesmo, seja eu executado no LINQPad ou em um aplicativo de consol

ntão, parece que o problema está em algum lugar no Entity Framewor

Estou fazendo algo errado aqui? Esta é uma parte do meu código com tempo crítico, então há algo que posso fazer para acelerar o desempenho?

Estou usando o Entity Framework 4.1 e o Sql Server 2008 R

UPDATE 1:

Na discussão abaixo, houve algumas perguntas sobre se o atraso ocorreu enquanto a EF estava criando a consulta inicial ou enquanto analisava os dados que recebeu de volta. Para testar isso, executei o seguinte 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();

que força EF a gerar a consulta sem executá-la no banco de dados. O resultado foi que esse código exigia ~ 20 segundos para ser executado; portanto, parece que quase todo o tempo é gasto na criação da consulta inicia

CompiledQuery para o resgate então? Não é tão rápido ... O CompiledQuery exige que os parâmetros passados para a consulta sejam tipos fundamentais (int, string, float etc.). Ele não aceita matrizes ou IEnumerable, portanto, não posso usá-lo para uma lista de ID

questionAnswers(8)

yourAnswerToTheQuestion