8

Mam metodę w moim generowanego częściowej klasy tak:.Skip() Take() na Entity Framework Właściwości nawigacji wykonuje SELECT * na moim SQL Server

var pChildren = this.Children 
    .Skip(skipRelated) 
    .Take(takeRelated) 
    .ToList(); 

Kiedy patrzę na mojego serwera SQL , Widzę, że wygenerowany kod robi kod SELECT *.* FROM Children Ten kod pochodzi bezpośrednio z mojej klasy. Sprawdziłem, czy kolejność mojego Skip/Take jest PRZED moją .ToList.

Jeśli usunąć .ToList, że linia jest szybka (i nie SQL jest wysyłane do mojego DB), ale moment staram się foreach nad wynikami, mam ten sam SQL wysyłane do mojego DB: SELECT *.* FROM Children.

Czy jest coś szczególnego, co muszę zrobić podczas korzystania z .Potkania i .Take na właściwości nawigacji moich obiektów?

aktualizacja

Postaram się uzyskać rzeczywiste SQL generowane, nie jestem obecnie setup do tego. Znalazłem pierwszy, ponieważ pojawia się na liście "recenty drogich zapytań" SSMS.

Running to:

var pChildren = this.Children 
    //.Skip(skipRelated) 
    //.Take(takeRelated) 
    .ToList(); 

powraca ~ 4.000.000 wierszy i trwa ~ 25 sekund.

Running to:

var pChildren = this.Children 
    //.Skip(skipRelated) 
    .Take(takeRelated) 
    .ToList(); 

powraca ~ 4.000.000 wierszy i trwa ~ 25 sekund.

Jak już powiedziałem, pobieram wygenerowany SQL dla nich i również je zgłaszam.

+0

Co SQL nie można oczekiwać, aby wygenerować ten kod? – cdhowie

+0

Miałem nadzieję na coś takiego jak "WYBIERZ TOP 10 OD DZIECI GDZIE ParentID = @ idOfParentEntity" (Zapomniałem, jak EF radzi sobie z .Skipem, ale czytałem, że powinno to zrobić.Jeśli wykonam to zapytanie bezpośrednio w moim kontekście, wydaje mi się, że ograniczyć dane zwrócone do konkretnej "strony") – Nate

+0

Obecność '.Skip()' wyklucza użycie 'TOP'. O ile nie spodziewałeś się, że zsumuje 'skipRelated' i' takeRelated' i użyje tego jako parametru 'TOP' ... który może być optymalizacją, ale może również nie mieć wpływu na wydajność. – cdhowie

Odpowiedz

7

Problemem jest to, że wykonują kwerendy LINQ-Object podczas przeszukiwania kolekcji dziecięcej takiego. EF załaduje całą kolekcję i wykona zapytanie w pamięci.

Jeśli używasz EF 4 można zapytać jak to

var pChildren = this.Children.CreateSourceQuery() 
       .OrderBy(/* */).Skip(skipRelated).Take(takeRelated); 

EF 4.1

var pChildren = context.Entry(this) 
        .Collection(e => e.Children) 
        .Query() 
        .OrderBy(/* */).Skip(skipRelated).Take(takeRelated) 
        .Load(); 
+0

Dokładnie to, czego potrzebowałem. Używam EF4.1, ale pierwsze zapytanie działa lepiej dla mnie, ponieważ nie mam dostępu do mojego kontekstu z tej konkretnej metody. – Nate

1

Czy to pomoże, jeśli zadzwonisz pod numer Skip na wynik Take? tj

table.Take(takeCount+skipCount).Skip(skipCount).ToList() 

również zobaczyć

+5

Zrobić zanim pominąć nie ma sensu – vittore

+1

@vittore: Oczywiście, że tak. Jeśli chcesz nagrywać 51-100, zamiast zdobyć milion klientów, wyrzucić 50, zatrzymać 50 i wyrzucić resztę, możesz pobrać 100 do klienta i wyrzucić 50. –

+0

@BenVoigt Chociaż to prawda, to nie pomaga tak bardzo, jak na ostatniej stronie. – Nate

Powiązane problemy