2012-12-18 16 views
5

Ich habe eine Tabelle von 200.000 Rekord, wo ich nur die Top 10 mit .Take() bekomme, aber es dauert etwa 10 Sekunden, um die Daten zu erhalten.Linq zu Entitäten ist sehr langsam mit .Take() -Methode

Meine Frage ist: Ruft die .Take() Methode alle Daten aus der Datenbank und Filter die Top 10 auf der Clientseite?

Hier ist mein Code:

mylist = (from mytable in db.spdata().OrderByDescending(f => f.Weight) 
            group feed by mytable.id into g 
            select g.FirstOrDefault()).Take(10).ToList(); 

spdata() ist eine Funktion Import von gespeicherten Prozedur.

Dank

+7

Wenn Sie neugierig sind, was es der Datenbank läuft gegen Sie einen Profiler Haken sollte bis zu Ihrer DB & überprüfen Sie die Protokolle, das ist der beste Weg, um herauszufinden. – Chris

+1

Wenn spdata() die 200.000 dann ja zurückgibt, wird es auf der Clientseite tun. –

+0

Zusätzlich zu Chris 'Methode können Sie auch Linqpad ausprobieren und nach dem Schreiben Ihrer Abfrage in die SQL-Ansicht wechseln, um das generierte SQL zu sehen, oder einen Haltepunkt setzen (mit dieser Methode http://stackoverflow.com/questions/1412863/how -do-i-view-the-sql-generierte-durch-die-Entität-Framework), um zu sehen, was beim Ausführen des Programms generiert wird. –

Antwort

8

Die gespeicherte Prozedur gibt wahrscheinlich sehr viele Daten an den Client zurück, was sehr langsam ist. Sie können eine Abfrage nicht an einen Sproc absetzen. Dies wäre mit einer Ansicht oder einer Tabellenwertfunktion möglich.

Es gibt keine Möglichkeit, einen Sproc in einer Abfrage zu verwenden. Sie können es nur selbst ausführen.

Ihre Absicht war wahrscheinlich, die Take(10) auf dem Server auszuführen. Damit dies funktioniert, müssen Sie zu einer Inline-Abfrage, einer Ansicht oder einem TVF wechseln.

6

Die Erweiterung Methode Take tut nicht alle Ergebnisse aus der Datenbank holen. So funktioniert Take nicht.

Allerdings ruft Ihr db.spdata() Aufruf wahrscheinlich alle Zeilen ab.

1

Ich bin nicht 100% sicher, aber ich erinnere Sie ein IEnumerable Ergebnis erhalten, wenn Sie einen SP mit EF Datacontext nennen ...

Es gibt ein paar war es, die Leistung zu optimieren:

  • Übergeben Sie die Suchkriterien s als SP-Parameter und führen Sie die Filterung in der gespeicherten Prozedur aus.

Oder wenn Sie eine ganz einfache Abfrage in der SP, wo Sie keine Variablen deklarieren und wo Sie schließen sich nur ein paar Tische dann:

  • eine indizierte Sicht erstellen, wo die Abfrage angeben, dass Sie brauche und rufe die Take-Methode auf.
    Was wird dir das geben? Sie können der erstellten Ansicht zuordnen und EF wird jetzt ein IQueryable-Ergebnis und kein IEnumerable zurückgeben. Dadurch wird der Befehl sql optimiert und stattdessen alle Daten empfangen und dann die 10 Elemente, die Sie benötigen, erstellt. Ein SQL-Befehl, der nur die 10 Elemente abruft, wird gebildet.

Ich rate Ihnen auch zu sehen, was ist die Differenz zwischen IEnumerable vs IQueryable.

0

Es tut, weil Sie die Daten vor dem Gruppieren sortieren, was in SQL nicht möglich ist.

sollten Sie ein Aggregat verwenden das höchste Gewicht von jeder Gruppe zu erhalten, dann die Gewichte sortieren, um die zehn größten zu bekommen:

mylist = (
    from mytable in db.spdata() 
    group feed by mytable.id into g 
    select g.Max(f => f.Weight) 
).OrderByDescending(w => w).Take(10).ToList(); 
+0

es gibt einen Fehler Fehler "Eine lokale Variable mit dem Namen 'g' kann nicht in diesem Bereich deklariert werden, da es 'g' eine andere Bedeutung geben würde, die bereits in einem 'übergeordneten oder aktuellen' Bereich verwendet wird, um etwas anderes zu bezeichnen" –

+0

@AliIssa: Richtig, da muss es eine andere Variable geben. Ich habe es geändert. – Guffa