Mise à JOUR 3: Selon cette annonce, cette question a été traitée par l'équipe EF dans EF6 alpha 2.
Mise à JOUR 2: j'ai créé une suggestion pour résoudre ce problème. Pour voter, rendez-vous ici.
Considérons une base de données SQL avec une table très très simple.
CREATE TABLE Main (Id INT PRIMARY KEY)
- Je remplir la table avec 10 000 enregistrements.
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)
- Je construire un modèle EF de la table et exécutez la requête suivante dans LINQPad (je suis à l'aide de "C# Déclarations" mode LINQPad ne pas créer un dump automatiquement).
var rows =
Main
.ToArray();
Le temps d'exécution est d'environ 0,07 seconde. Maintenant, j'ajoute l'opérateur Contient et de ré-exécuter la requête.
var ids = Main.Select(a => a.Id).ToArray();
var rows =
Main
.Where (a => ids.Contains(a.Id))
.ToArray();
Le temps d'exécution pour ce cas est 20.14 secondes (288 fois plus lent)!
Au début, je soupçonne que le T-SQL émis pour la requête a été plus long à exécuter, donc j'ai essayé de les couper et coller à partir LINQPad du volet SQL dans 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,...
Et le résultat a été
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 88 ms.
Ensuite, j'ai soupçonné LINQPad a été à l'origine du problème, mais la performance est la même, que je le lance dans LINQPad ou dans une application console.
Donc, il semble que le problème est quelque part à l'intérieur de l'Entity Framework.
Suis-je en train de faire quelque chose de mal ici? C'est une partie essentielle de mon code, donc, il y a quelque chose que je peux faire pour accélérer les performances?
Je suis à l'aide de Entity Framework 4.1 et Sql Server 2008 R2.
Mise à JOUR 1:
Dans la discussion ci-dessous, il y avait quelques questions au sujet de si le retard s'est produit alors que les EF de la construction de la requête initiale ou alors qu'il était de l'analyse des données, il a reçu en retour. Pour tester cela, j'ai couru le code suivant
var ids = Main.Select(a => a.Id).ToArray();
var rows =
(ObjectQuery<MainRow>)
Main
.Where (a => ids.Contains(a.Id));
var sql = rows.ToTraceString();
qui des forces EF pour générer la requête sans l'exécuter sur la base de données. Le résultat est que ce code ~20 secords à courir, de sorte qu'il semble que presque tous les temps est pris dans la construction de la requête initiale.
CompiledQuery à la rescousse? Pas si vite ... CompiledQuery exige que les paramètres passés à la requête fondamentaux types (int, string, float, et ainsi de suite). Il n'accepte pas les groupes ou les IEnumerable, donc je ne peux pas l'utiliser pour une liste d'Id.