La requête Entity Framework est lente, mais le même SQL dans SqlQuery est rapide

Je vois un perf très étrange lié à une requête très simple utilisant Entity Framework Code-First avec .NET Framework version 4. La requête LINQ2Entities ressemble à ceci:

context.MyTables.Where(m => m.SomeSsortingngProp == ssortingngVar); 

Cela prend plus de 3000 millisecondes à exécuter. Le code SQL généré est très simple:

  SELECT [Extent1].[ID], [Extent1].[SomeSsortingngProp], [Extent1].[SomeOtherProp], ... FROM [MyTable] as [Extent1] WHERE [Extent1].[SomeSsortingngProp] = '1234567890' 

Cette requête s’exécute presque instantanément lorsqu’elle est exécutée via Management Studio. Lorsque je change le code C # pour utiliser la fonction SqlQuery, il s’exécute en 5-10 millisecondes:

  context.MyTables.SqlQuery("SELECT [Extent1].[ID] ... WHERE [Extent1].[SomeSsortingngProp] = @param", ssortingngVar); 

Donc, exactement le même SQL, les entités résultantes sont suivies de changement dans les deux cas, mais la différence de performance entre les deux. Ce qui donne?

Trouvé Il s’agit d’un problème de type de données SQL. La colonne SomeSsortingngProp de la firebase database était un varchar, mais EF suppose que les types de chaîne .NET sont nvarchars. Le processus de traduction résultant lors de la requête de la firebase database pour effectuer la comparaison prend du temps. Je pense qu’EF Prof me conduisait un peu en erreur, une représentation plus précise de la requête en cours d’exécution serait la suivante:

  SELECT [Extent1].[ID], [Extent1].[SomeSsortingngProp], [Extent1].[SomeOtherProp], ... FROM [MyTable] as [Extent1] WHERE [Extent1].[SomeSsortingngProp] = N'1234567890' 

Le correctif résultant consiste donc à annoter le modèle du code en premier, en indiquant le type de données SQL correct:

 public class MyTable { ... [Column(TypeName="varchar")] public ssortingng SomeSsortingngProp { get; set; } ... } 

La raison de ralentir mes requêtes dans EF était de comparer des scalaires non nullables à des scalaires nullables:

 long? userId = 10; // nullable scalar db.Table().Where(x => x.User.Id == userId).ToList() // or userId.Value ^^^^^^^^^ ^^^^^^ Type: long Type: long? 

Cette requête a pris 35 secondes. Mais un petit refactoring comme ça:

 long? userId = 10; long userIdValue = userId.Value; // I've done that only for the presentation pursposes db.Table().Where(x => x.User.Id == userIdValue).ToList() ^^^^^^^^^ ^^^^^^^^^^^ Type: long Type: long 

donne des résultats incroyables. Il n’a fallu que 50 ms pour terminer. Il est possible que ce soit un bug dans EF.

Si vous utilisez le mappage fluide, vous pouvez utiliser IsUnicode(false) dans le cadre de la configuration pour obtenir le même effet –

http://msdn.microsoft.com/en-us/data/jj591617.aspx#1.9

http://msdn.microsoft.com/en-us/library/gg696416%28v=vs.103%29.aspx

J’ai eu le même problème (la requête est rapide lorsqu’elle est exécutée à partir du gestionnaire SQL) mais lorsqu’elle est exécutée depuis EF, le délai expire.

Il s’avère que l’entité (qui a été créée à partir de la vue) avait des clés d’entité incorrectes. Donc, l’entité avait des lignes en double avec les mêmes clés, et je suppose que cela devait faire du regroupement en arrière-plan.

Je suis également tombé sur cela avec une requête ef complexe. Un correctif pour moi qui réduisait une requête ef de 6 secondes à la seconde requête SQL générée était de désactiver le chargement différé.

Pour trouver ce paramètre (ef 6), accédez au fichier .edmx et recherchez dans Propriétés -> Génération de code -> Chargement paresseux activé. Défini sur false.

Amélioration massive de la performance pour moi.

Vous pouvez utiliser les astuces suivantes pour fixer vos requêtes –

  1. Définissez ctx.Configuration.ProxyCreationEnabled sur false juste avant d’obtenir le contexte.
  2. En outre, .Select(c => new {c.someproperty}) ne récupèrera que les données requirejses et non le groupe entier.

Faites-moi savoir si cela a aidé.

J’ai eu ce problème aussi. Il s’avère que le coupable dans mon cas était le paramètre SQL-Server reniflant .

Le premier indice que mon problème était dû à la détection des parameters était que l’exécution de la requête avec “set arithabort off” ou “set arithabort on” entraînait des temps d’exécution radicalement différents dans Management Studio. En effet, ADO.NET utilise par défaut “set arithabort off” et Management Studio par défaut “set arithabort on”. Le cache du plan de requête conserve différents plans en fonction de ce paramètre.

J’ai désactivé la mise en cache du plan de requête pour la requête, avec la solution que vous pouvez trouver ici .