2010-08-26 8 views
11

I der Art die ganze erfassen Ausführung Konzept verzögert, aber die folgenden Dokumente verwirrt mich ...Langsam foreach() auf einer LINQ-Abfrage - ToList() steigert die Leistung immens - warum ist das?

Auf einer Datentabelle etwa 1000 Zeilen enthält, nenne ich AsEnumerable(). Ich wähle dann die in einem IEnumerable stark typisierten Klassen zurückgegebene Entitäten (1) ... Hier ist, wo ich verwirrt bin: Ich mache eine foreach-Schleife auf die Sammlung; Auswahl von Sachen aus den einzelnen Artikeln in der Sammlung mit einer Reihe von Where() Anrufe (2) ... Und es ist tot langsam.

  1. DataTable.AsEnumerable().Select(r => new ObjectRepresentation { ... });
  2. item.Where(i => i.SomeEnum == SomeEnum.Something)


... Aber wenn ich ToList() aufrufen gleich nach meinem AsEnumerable() Anruf auf dem Datatable, die foreach Die Schleife dauert weniger als eine Sekunde.

Was fehlt mir hier? Rufe ich effektiv AsEnumerable() jedes Mal, wenn meine Schleife iteriert? Oder jedes Mal, wenn ich auf ein Objekt in der Sammlung zugreife? Oder jedes Mal, wenn ich eine Where() Anruf auf ein Element in der Sammlung machen? Oder alles oben genannte?


aktualisieren

Etwas vollständige Code:

public class ObjectRepresentation 
{ 
    public SomeEnum SomeEnum { get; set; } 
} 


var collection = DataTable.AsEnumerable().Select(r => new ObjectRepresentation 
{ 
    SomeEnum = (SomeEnum)Convert.ToInt32(r["SomeEnum"]) 
}); 

foreach(var item in collection) // slow loop 
{ 
    // 10 or so Where() calls on item inside this loop 
} 

collection = collection.ToList(); // Hit hyper speed button! 

foreach(var item in collection) // fast loop 
{ 
    // 10 or so Where() calls on item inside this loop 
} 
+3

Klingt so, als würden Sie bei jeder Iteration einen Datenbankaufruf ausführen. Sie könnten den SQL Profiler ausführen, um zu sehen, ob das wahr ist ... –

+0

Warum AsEnumerable() aufrufen? AsEnumerable ändert ein Objekt zur Kompilierzeit in IEnumerable , wenn es bereits IEnumerable implementiert. Warum iterieren Sie die Zeilen nicht mithilfe der Rows-Eigenschaft einer Tabelle? – Wix

+1

@Wix: 'DataTable' implementiert 'IEnumerable ' nicht bereits. Wenn Sie 'AsEnumerable' auf einer' DataTable' aufrufen, rufen Sie die 'DataTableExtensions.AsEnumerable' Methode auf, * nicht *' Enumerable.AsEnumerable'. http://msdn.microsoft.com/en-us/library/system.data.datatableextensions.asenumerable.aspx – LukeH

Antwort

7

Es wird nicht alle Artikel aus der Datenbank erhalten, bis Sie

ToList or First or Single 

In foreach geben Sie für jedes Element eine Abfrage in der Datenbank senden. Es funktioniert also langsamer. Öffnen Sie Ihren SQL Profiler, um besser zu verstehen.

+1

In dem bestimmten Szenario des OPs verursacht er möglicherweise eine Datenbankabfrage für jeden wiederholten Datensatz, aber es ist * nicht * wahr, dass das Aufzählen einer verzögerten Abfrage mit foreach jedes Element separat abfragt. Die gesamte Sammlung wird abgerufen, wenn der Enumerator zum ersten Mal verwendet wird. –

+2

Er fragt eine Datentabelle ab, keinen Linq DataContext oder ObjectContext. Es gibt keine Möglichkeit, dass eine Abfrage auf der Datentabelle eine DB-Abfrage ausführen würde –

+2

yep, Sie haben Recht. Aber das ist eine allgemeine Erklärung, um zu verstehen, was Linq mit Methoden macht. Für jedes Element wird es einige Zeit dauern, bis Daten für mehr als die Verwendung von ToList für jede Anweisung abgerufen werden. – NetSide

10

Sie verstehen nicht, welche Methoden abgegrenzt sind und welche nicht, so dass Sie nicht verstehen, wenn Ihr Code-Operationen definiert vs führt Operationen durch.

Diese sind alle zurückgestellt. Sie definieren eine Operation, führen sie aber nicht aus.

source.AsEnumerable 
source.Select 
source.Where 

Diese zählen die Quelle auf und werden nicht zurückgestellt.

source.ToList 
source.First 
source.Single 
foreach(var x in source) 
+1

Können Sie es ausarbeiten? – roosteronacid

+4

Ja kann ich. Auf was? –

0

In der Tat scheinen Sie keine klare Vorstellung davon zu haben, was Codeausführung ist und was die Definition der Absicht ist (möglicherweise) später auszuführen, wenn die Ergebnisse tatsächlich verwendet werden. Ich schlage vor, einen Teil von LINQ zu lesen.

Und möglicherweise versuchen, beide Ihrer Varianten mit einem Debugger angeschlossen, so dass Sie tatsächlich sehen können, welcher Code in welcher Reihenfolge ausgeführt wird und was tatsächlich mit Ihren Daten passiert. Sie könnten hier eine (große?) Überraschung erleben ...

Verwandte Themen