2010-08-26 11 views
11

I tipi di cogliere il tutto in ritardo concetto di esecuzione, ma le seguenti ha mi ha sconcertato ...Slow foreach() su una query LINQ - ToList() aumenta enormemente le prestazioni: perché?

Su un DataTable contenente circa 1000 righe, io chiamo AsEnumerable(). Quindi seleziono le entità restituite in un IEnumerable di classi fortemente tipizzate (1) ... Ecco dove mi confondo: eseguo un ciclo foreach sulla raccolta; selezionando le cose dai singoli elementi della collezione utilizzando un gruppo di Dove() chiamate (2) ... Ed è lento.

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


... Ma se io chiamo ToList() subito dopo il mio AsEnumerable() chiamata sul DataTable, il foreach il ciclo richiede meno di un secondo per essere completato.

Cosa mi manca qui? Sto effettivamente chiamando AsEnumerable() ogni volta che il mio ciclo itera? O ogni volta che accedo a un articolo nella collezione? O ogni volta che eseguo una chiamata Dove() su un articolo nella raccolta? O tutto quanto sopra?


Aggiornamento

codice Un po 'completo:

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

Sembra che si stia eseguendo una chiamata al database a ogni iterazione. È possibile eseguire SQL Profiler per vedere se è vero ... –

+0

Perché chiamare AsEnumerable()? AsEnumerable modifica un oggetto in fase di compilazione a IEnumerable se implementa già IEnumerable . Perché non iterare le righe utilizzando la proprietà Rows di una tabella? – Wix

+1

@Wix: 'DataTable' non implementa già' IEnumerable '. Quando chiami 'AsEnumerable' su un' DataTable' stai chiamando il metodo 'DataTableExtensions.AsEnumerable', * not *' Enumerable.AsEnumerable'. http://msdn.microsoft.com/en-us/library/system.data.datatableextensions.asenumerable.aspx – LukeH

risposta

7

Non otterrà tutte le voci dal database fino a quando si digita

ToList or First or Single 

In foreach, si invia una query nel database per ogni elemento. Quindi funziona più lentamente. Apri il tuo SQL Profiler per capire meglio.

+1

Nello scenario particolare dell'OP, potrebbe causare l'esecuzione di una query di database per ogni record iterato, ma in * non * true in generale che l'enumerazione di una query posticipata con foreach interroga ogni voce separatamente. L'intera raccolta viene recuperata quando viene utilizzato per la prima volta l'enumeratore. –

+2

Sta interrogando un datatable, non un DataContext Linq o ObjectContext. Non c'è modo in cui una query sul datatable causerà l'esecuzione di una query DB –

+2

sì, hai ragione. Ma questa è una spiegazione generale per capire cosa fa linq con i metodi. Per ogni articolo, ci vorrà del tempo per ottenere dati più che usare ToList prima per ogni affermazione. – NetSide

10

Non si capisce quali metodi vengono differiti e quali no, quindi non si capisce quando il codice definisce le operazioni vs esegue operazioni.

Questi sono tutti differiti. Definiscono, ma non eseguono, un'operazione.

source.AsEnumerable 
source.Select 
source.Where 

Questi enumerano la sorgente e quindi non vengono differiti.

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

Puoi elaborare? – roosteronacid

+4

Sì, posso. Su cosa? –

0

In effetti non sembra avere una chiara idea di cosa sia l'esecuzione del codice e quale sia la definizione dell'intenzione di (eventualmente) eseguire più tardi quando i risultati vengono effettivamente utilizzati. Suggerisco di leggere una parte di questo LINQ.

E possibilmente provare a eseguire entrambe le varianti con un debugger collegato in modo da poter effettivamente vedere quale codice è in esecuzione in quale ordine e ciò che sta realmente accadendo ai dati. Potresti essere in una (grande?) Sorpresa qui ...

Problemi correlati