2016-06-20 29 views
0

Dies ist eine LINQ-Abfrage, die zum Abrufen von Daten aus der Datenbank mit Entity Framework 7 verwendet wird. Es gibt ein Paar von .Where(x => x.CollectedMaterial.OrderByDescending(y => y.Repeats).First(). Gibt es eine Möglichkeit, diese Abfrage zu optimieren? Müssen Sie das tun oder EF optimiert es selbst?EF optimieren komplexe LINQ-Abfrage erforderlich?

+0

Alle Antworten sind für mich, dank all nützlich verschmelzen! – AsValeO

Antwort

2

AFAIK Sie sollten keine where-Klausel verwenden, um eine Liste herauszufiltern, sondern die Bedingung in eine where-Klausel zu setzen.

EDIT: ja, es scheint in Ordnung zu sein zu verwenden multiple where clauses auch

Tipps: alle in der Abfrage die Daten versuchen, um herauszufiltern sich auf das In-Memory-Objekt nicht filtern, indem unnötigen Daten zu erhalten, vielleicht selbst unnötige Felder können Sie mit einer Projektionsoperation nur die erforderlichen Felder auswählen.

Die Antworten here sagen auch so, ich in der Regel für ein Gleichgewicht gehen b/w Lesbarkeit und Leistung, die Sie versuchen sollten, wie viel Performance-Verbesserung zu bewerten erforderlich wäre, auch Visual Studio Profiler versuchen, es hat Speicher, CPU-Sampling etc.

Wenn Sie diesen Code in einer get-Methode schreiben, können Sie die AsNoTracking-Methode für das DbSet verwenden, was die Leistung verbessert, da das Entity Framework es nicht mit den standardmäßig erstellten Tracking-Objekten verfolgt.

Verwenden Sie die Database.Log -Eigenschaft auf Ihrem DbContext -Objekt, um die generierte SQL-Abfrage zu protokollieren und zu sehen, indem Sie den Code ändern, der komplexe Abfrage scheint, wird dies Ihnen helfen.

Sie können als context.Database.Log = Console.WriteLine;

in Console App einloggen Sie in einer anderen Anwendung zu Debug oder Trace als context.Database.Log = message => Trace.WriteLine(message); anmelden können

+0

Danke, viele nützliche Dinge. Sieht aus wie mehrere '.Where()' ist ok für 'IQueryable' (Petrs Antwort). – AsValeO

+1

Ja, es scheint in Ordnung zu sein, mehrere .Where() -Klauseln zu verwenden, würde ich sagen, dass es die Lesbarkeit des Codes verbessern könnte. –

1

Da Sie mit IQueryable arbeiten, können Sie die Kette Sie .Where() Bedingungen so viel wie Sie Alles was du erstellst ist ein Ausdrucksbaum, der später ausgewertet wird.

Wenn Sie die Daten tatsächlich aus der Datenbank abrufen (wie in Ihrem Beispiel ToList()), erstellt die EF dann eine optimierte SQL-Abfrage.

Dann kommt es darauf an ... das Beste, was Sie tun können, ist SQL-Profiler gegen Ihre DB ausführen und fangen und sehen tatsächlich generiert Abfrage von EF.

1

AFAIK, Entity optimiert alles, bis der eigentliche db-Aufruf realisiert wird. In Ihrem Fall wird dann der Anruf an .ToListAsync getätigt.

EDIT: Sehen this Kommentar, es scheint, Sie sollten alle Abfragen zusammenführen. Denken Sie dennoch daran, die variable Definition zu verwenden, wenn Sie können.

In Bezug auf die Optimierung, können Sie

.Where(x => x.CollectedMaterial.OrderByDescending(y => y.Repeats).First().Repeats >= firstRepeatsCount) 
.Where(x => x.CollectedMaterial.OrderByDescending(y => y.Repeats).First().MaterialID != x.MaterialID) 

zu

.Where(x => { 
    var firstRepeats = x.CollectedMaterial.OrderByDescending(y => y.Repeats).First().Repeats; 
    return (firstRepeats.Repeats >= firstRepeatsCount && 
      firstRepeats.MaterialID != x.MaterialID) }) 

(ungetestet, obwohl)

+0

Leider ist es nicht möglich Statement Body mit 'IQueryable' zu ​​verwenden" Ein Lambda-Ausdruck mit einem Statement Body kann nicht in einen Ausdrucksbaum konvertiert werden ". – AsValeO

+0

Und Sie sollten die Daten nicht vor der Verwendung extrahieren, sonst würden Sie Ihre Leistung ruinieren. – torendil