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

Je vois un perf vraiment étrange lié à une requête très simple en utilisant le code Entity Framework-D'abord avec.NET framework version 4. La requête LINQ2Entities ressemble à ceci:

 context.MyTables.Where(m => m.SomeStringProp == stringVar);

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

 SELECT [Extent1].[ID], [Extent1].[SomeStringProp], [Extent1].[SomeOtherProp],
 ...
 FROM [MyTable] as [Extent1]
 WHERE [Extent1].[SomeStringProp] = '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].[SomeStringProp] = @param", stringVar);

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

61
demandé sur Michael Sandler 2013-04-02 19:16:13

7 réponses

Trouvé. Il s'avère que c'est un problème de types de données SQL. La colonne SomeStringProp de la base de données était un varchar, mais EF suppose que les types de chaînes. Net sont des nvarchars. Le processus de traduction résultant pendant la requête pour que la base de données fasse la comparaison est ce qui prend beaucoup de temps. Je pense que EF Prof m'égarait un peu ici, une représentation plus précise de la requête en cours d'exécution serait la suivante:

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

Donc, le correctif résultant est d'Annoter le modèle code-first, indiquant le type de données SQL correct:

public class MyTable
{
    ...

    [Column(TypeName="varchar")]
    public string SomeStringProp { get; set; }

    ...
}
65
répondu Brian Sullivan 2013-04-02 19:39:05

La raison de ralentir mes requêtes faites dans EF était de comparer des scalaires Non nullables avec des scalaires nullables:

long? userId = 10; // nullable scalar

db.Table<Document>().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<Document>().Where(x => x.User.Id == userIdValue).ToList()
                                ^^^^^^^^^    ^^^^^^^^^^^
                                Type: long   Type: long

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

31
répondu cryss 2016-03-07 10:47:01

Si vous utilisez le mappage fluent, 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

6
répondu Matt 2013-08-25 20:36:01

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

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

2
répondu Vladimir Gedgafov 2013-04-12 18:01:28

Je suis également tombé sur cela avec une requête ef complexe. Un correctif pour moi qui a réduit une requête ef de 6 secondes à la seconde requête sql qu'elle a générée était de désactiver le chargement paresseux.

Pour trouver ce paramètre (ef 6) Aller à la .fichier edmx et regardez dans les propriétés - > génération de Code - > chargement paresseux activé. La valeur false.

Amélioration Massive des performances pour moi.

2
répondu user2622095 2014-05-30 11:40:14

, 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, {[2] } ne récupérera que les données requises et non tout le groupe.

Faites-moi savoir si cela a aidé.

1
répondu Rajesh Panda 2017-09-16 20:30:43

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

Le premier indice que mon problème était en fait dû au reniflage des paramètres était que l'exécution de la requête avec "set arithabort off" ou "set arithabort on" donnait des temps d'exécution radicalement différents dans Management Studio. C'est parce que ADO.NET par défaut utilise "set arithabort off" et Management Studio par défaut à "set arithabort on". Le cache du plan de requête conserve des plans différents 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.

1
répondu Oskar Sjöberg 2018-08-23 10:35:09