2009-02-16 15 views
10

Ich verwende IQueryable<T> Schnittstellen während meiner Anwendung und verschieben die Ausführung von SQL auf der DB bis Methoden wie .ToList()zählen VS in LINQ auswählen - was ist schneller?

Ich muss den Grafen von bestimmten Listen manchmal finden -without- um die Daten in der Liste zu bedienen ist gezählt. Ich weiß aus meiner SQL-Erfahrung, dass ein SQL COUNT() viel weniger Arbeit für die DB als die äquivalente SELECT-Anweisung ist, die alle Zeilen zurückgibt.

Also meine Frage ist: Wird es weniger Arbeit an der DB, die Zählung von den IQueryable<T> ‚s Count() Methode zurückzukehren, als die IQueryable<T> auf eine Liste zu machen und das Aufrufen der Count()-Methode der Liste?

Ich vermute, es wird gegeben, dass die ToList() wird die SELECT sql und dann in einer separaten Abfrage die Zeilen zählen. Ich hoffe, dass die Count() auf der IQueryable<T> einfach die SQL für eine SQL COUNT() Abfrage stattdessen ausgibt. Aber ich bin mir nicht sicher. Wissen Sie?

Antwort

20

Aufruf ToList() wird eine echte List<T> mit allen Daten zurückgeben, was bedeutet, dass alle Daten abgerufen werden. Nicht gut.

Aufruf Count() sollte in der Tat die SQL auf der Datenbankseite die Zählung ausführen. Viel besser.

Die einfachste Möglichkeit, dies zu überprüfen, besteht jedoch darin, die Protokollierung Ihres Datenkontexts (oder des entsprechenden Providers) zu aktivieren und festzustellen, welche Abfragen tatsächlich gesendet werden.

+0

danke Jon. Ich kann überprüfen, dass die Count() - Methode von IQQueryable die richtige SQL COUNT() und nicht die Count-Eigenschaft der Liste ausführt, die das SELECT ausgelöst haben muss. hier ist auch ein kool TextWriter für diejenigen, die das Logging beobachten wollen - http: //www.u2u.info/Blogs/Kris/Lists/Posts/Post.aspx? ID = 11 –

+1

Sql Server COUNT wird immer noch langsam sein, da es einen Tabellenscan verursacht! – Slaggg

+1

@Slaggg, wenn Sie einen Index haben, wird nur ein Index-Scan auf dem kleinsten Index durchgeführt, den Sie haben. Wenn Sie keine Indizes haben, wird die Netzwerklast auf dem Datenbankserver immer noch reduziert (im Vergleich zur Rückgabe aller Zeilen). –

-1

Ich bin mir nicht sicher, ob es eine harte und schnelle Regel ist, aber linq-Methode, die Sie zu einem Iqueryable hinzufügen, wird in den Linq-Ausdrucksbaum hinzugefügt - es sei denn, sie sind eine der Methoden, die tatsächlich die Auswertung des Baumes verursachen. wie ToList und Single etc). Im Fall von LinqToSql wissen Sie, ob es etwas in die SQL-Anweisung konvertieren kann, weil Sie eine Laufzeitausnahme erhalten, die besagt, dass die Methode nicht unterstützt wird.

zB

var something = dbContext.SomeTable 
    .Select(c => c.col1 == "foo") 
    .Distinct() 
    .ToList() 
    .Count() 

Im obigen Wählen Sie() und Distinct() in der SQL-Abfrage an den Server weitergeleitet enthalten, weil sie in ein IQueryable hinzugefügt werden. Count() handelt nur auf der Liste, die von der SQL-Abfrage zurückgegeben wurde. Also wollen Sie es nicht so machen :-)

In Ihrem Fall wird Count() definitiv schneller als Select(), weil die resultierende SQL-Anweisung tatsächlich die Anzahl enthalten wird, so dass der Server nur zurückkehren muss eine einzelne Nummer anstelle einer Liste von Zeilen.

-1

Wenn Sie SQL Server verwenden, ist Count() immer noch sehr teuer, weil es einen Tabellenscan (oder Indexscan, siehe Kommentare zur primären Antwort) verursacht. Und standardmäßig verwendet Linq nicht das unkompensierte Isolationslevel, was die Sperrung verschlimmert.

Wenn Sie mit dem Ergebnis ein schmutziges Ergebnis und eine Approximation der Gesamtzahl der Zeilen leben können, wird der folgende Code wesentlich schneller als mit Count(). Nach meiner Erfahrung unterscheidet sich der von diesem Code zurückgegebene Wert selten von der tatsächlichen Anzahl von Zeilen.

/// <summary>A very fast method for counting rows in a table.</summary> 
public static long FastRowCount(DataContext context, string tableName) 
{ 
    const string template = "SELECT rowcnt FROM sys.sysindexes WHERE id = OBJECT_ID('{0}') AND indid < 2"; 
    string query = string.Format(template, tableName); 
    return context.ExecuteQuery<long>(query).Single(); 
} 
+0

Es ist eine faire Annahme, dass alles, was in einer Produktionsumgebung überwacht wird, indiziert wird. –