Pourquoi Entity Framework prend-il 30 secondes pour charger des enregistrements alors que la requête générée ne prend que 1/2 seconde?

.net c# entity-framework linq-to-entities

Question

ExecuteTime ci-dessous correspond à 30 secondes la première fois et à 25 secondes la prochaine fois que j'exécute le même ensemble de code. Lorsque je regarde dans SQL Profiler, je vois tout de suite un identifiant, puis il reste là pendant environ 30 secondes. Ensuite, dès que l'instruction select est exécutée, l'application termine la commande ToList. Lorsque j'exécute la requête générée à partir de Management Studio, la requête de base de données ne prend qu'environ 400 ms. Il retourne 14 lignes et 350 colonnes. Il semble que le temps nécessaire à la transformation des résultats de la base de données en entités soit si petit que cela ne se remarque pas.

Alors que se passe-t-il dans les 30 secondes précédant l'appel de la base de données?

Si le cadre de l'entité est aussi lent, il ne nous est pas possible de l'utiliser. Y a-t-il quelque chose que je fais de travers ou que je peux changer pour accélérer le processus?

UPDATE: Très bien, si j'utilise une requête compilée, la première fois que cela prend 30 secondes et la deuxième fois, cela prend 1 / 4ème de seconde. Est-ce que je peux faire quelque chose pour accélérer le premier appel?

using (EntitiesContext context = new EntitiesContext()) 
{ 
    Stopwatch sw = new Stopwatch(); 
    sw.Start(); 
    var groupQuery = (from g in context.Groups.Include("DealContract") 
                    .Include("DealContract.Contracts") 
                    .Include("DealContract.Contracts.AdvertiserAccountType1") 
                    .Include("DealContract.Contracts.ContractItemDetails") 
                    .Include("DealContract.Contracts.Brands") 
                    .Include("DealContract.Contracts.Agencies") 
                    .Include("DealContract.Contracts.AdvertiserAccountType2") 
                    .Include("DealContract.Contracts.ContractProductLinks.Products") 
                    .Include("DealContract.Contracts.ContractPersonnelLinks") 
                    .Include("DealContract.Contracts.ContractSpotOrderTypes") 
                    .Include("DealContract.Contracts.Advertisers") 
                where g.GroupKey == 6 
                select g).OfType<Deal>(); 
    sw.Stop(); 
    var queryTime = sw.Elapsed; 
    sw.Reset(); 
    sw.Start(); 
    var groups = groupQuery.ToList(); 
    sw.Stop(); 
    var executeTime = sw.Elapsed; 
} 

Réponse acceptée

J'ai eu exactement le même problème, ma requête prenait 40 secondes.

J'ai trouvé que le problème .Include("table_name") fonctions .Include("table_name") . Plus j'en avais, plus c'était pire. Au lieu de cela, j'ai changé mon code en Lazy Load toutes les données dont j'avais besoin juste après la requête, ce qui a réduit le temps total à environ 1,5 seconde au lieu de 40 secondes. Autant que je sache, ceci accomplit exactement la même chose.

Donc, pour votre code, ce serait quelque chose comme ça:

var groupQuery = (from g in context.Groups
            where g.GroupKey == 6 
            select g).OfType<Deal>(); 

var groups = groupQuery.ToList();

foreach (var g in groups)
{
    // Assuming Dealcontract is an Object, not a Collection of Objects
    g.DealContractReference.Load();
    if (g.DealContract != null)
    {
        foreach (var d in g.DealContract)
        {
            // If the Reference is to a collection, you can just to a Straight ".Load"
            //  if it is an object, you call ".Load" on the refence instead like with "g.DealContractReference" above
            d.Contracts.Load();
            foreach (var c in d.Contracts)
            {
                c.AdvertiserAccountType1Reference.Load();
                // etc....
            }
        }
    }
}

Incidemment, si vous deviez ajouter cette ligne de code au-dessus de la requête dans votre code actuel, le temps serait ramené à environ 4-5 secondes (toujours trop lent dans mon option). De ce que je comprends, l'option MergeOption.NoTracking désactivée une grande partie de la surcharge de suivi liée à la mise à jour et à l'insertion d'éléments dans la base de données:

context.groups.MergeOption = MergeOption.NoTracking;

Réponse populaire

C'est à cause de l'inclusion. J'imagine que vous avez hâte de charger beaucoup d'objets dans la mémoire. Il faut beaucoup de temps pour créer les objets c # qui correspondent à vos entités de base de données.

Ma recommandation pour vous est d'essayer de charger paresseux uniquement les données dont vous avez besoin.



Related

Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow