Warum dauert es 30 Sekunden, bis Entity Framework Datensätze lädt, wenn die generierte Abfrage nur 1/2 Sekunde dauert?

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

Frage

Die ExecuteTime-Zeit beträgt beim ersten Mal 30 Sekunden und beim nächsten Ausführen des gleichen Codesatzes 25 Sekunden. Beim Anschauen in SQL Profiler sehe ich sofort ein Login, das dann etwa 30 Sekunden lang angezeigt wird. Sobald die select-Anweisung ausgeführt wird, beendet die App den Befehl ToList. Wenn ich die generierte Abfrage in Management Studio ausführen, dauert die Datenbankabfrage nur etwa 400 ms. Es gibt 14 Zeilen und 350 Spalten zurück. Es sieht so aus, als wäre die Umwandlung der Datenbankergebnisse in die Entitäten so klein, dass sie nicht wahrgenommen werden kann.

Was passiert also in den 30 Sekunden vor dem Aufruf der Datenbank?

Wenn das Entity-Framework so langsam ist, können wir es nicht verwenden. Gibt es etwas, was ich falsch mache, oder etwas, das ich ändern kann, um dies dramatisch zu beschleunigen?

UPDATE: Okay , wenn ich eine kompilierte Abfrage verwende, dauert es beim ersten Mal 30 Sekunden und beim zweiten Mal 1/4 einer Sekunde. Kann ich irgendetwas tun, um den ersten Anruf zu beschleunigen?

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; 
} 

Akzeptierte Antwort

Ich hatte genau das gleiche Problem, meine Abfrage dauerte 40 Sekunden.

Ich habe festgestellt, dass das Problem mit den Funktionen .Include("table_name") . Je mehr davon ich hatte, desto schlimmer war es. Stattdessen habe ich meinen Code in Lazy Load geändert. Laden Sie alle benötigten Daten direkt nach der Abfrage. Dies hat die Gesamtzeit von 40 Sekunden auf etwa 1,5 Sekunden verkürzt. Soweit ich weiß, wird damit genau dasselbe erreicht.

Für Ihren Code würde es also so aussehen:

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

Übrigens, wenn Sie diese Codezeile oberhalb der Abfrage in Ihren aktuellen Code einfügen würden, würde dies die Zeit auf etwa 4-5 Sekunden MergeOption.NoTracking (in meiner Option immer noch zu lang). MergeOption.NoTracking Option MergeOption.NoTracking meines MergeOption.NoTracking deaktiviert Ein Großteil des Tracking-Overheads für das Aktualisieren und Einfügen von Daten in die Datenbank:

context.groups.MergeOption = MergeOption.NoTracking;

Beliebte Antwort

Es liegt am Include. Meine Vermutung ist, dass Sie gerne viele Objekte in den Speicher laden. Es dauert viel Zeit, die c # -Objekte zu erstellen, die Ihren DB-Entitäten entsprechen.

Meine Empfehlung für Sie ist, zu versuchen, nur die Daten zu laden, die Sie benötigen.



Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum