2010-08-17 10 views
10

Mam relacji tabela nadrzędny podrzędność. W repozytorium, to robię:EF na zawsze generuje to zapytanie

return (from p in _ctx.Parents 
.Include("Children") 
select p).AsQueryable<Parent>(); 

Następnie w filtrze, chcę filtrować rodzica przez listę identyfikatorów podrzędnych:

IQueryable<Parent> qry; // from above 
List<int> ids; // huge list (8500) 
var filtered = 
from p in qry.Where(p => p.Children.Any(c => ids.Contains(c.ChildId))) select s; 

Moja lista identyfikatorów jest ogromna. Generuje to prostą instrukcję SQL, która ma ogromną listę identyfikatorów "w (1,2,3 ...)", ale samo uruchomienie nie zajmuje znaczącego czasu. EF jednak zajmuje około minuty, aby wygenerować wyciąg. Udowodniłem to, ustawiając punkt przerwania i dzwoniąc pod numer:

((ObjectQuery<Parent>)filtered).ToTraceString(); 

Zajmuje to cały czas. Czy problem występuje w moim ostatnim wyciągu linq? Nie znam innego sposobu na zrobienie odpowiednika Child.ChildId in (ids). I nawet jeśli moja instrukcja linq jest zła, jak na świecie powinno to potrwać tak długo?

+0

Opublikuj swój schemat i wygenerowany sql, możesz uzyskać dodatkową pomoc. –

+0

Schemat nie ma znaczenia, podobnie jak relacja rodzic/dziecko. Ten sam problem polega na wybraniu pojedynczej tabeli/obiektu z dużą listą. – dudeNumber4

+0

Dla każdego, kto ma problem; ze wszystkiego, co mogę powiedzieć, nie ma rozwiązania z EF4. Musisz uciekać się do procedur przechowywanych. Więcej informacji: http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/d629c798-db45-4a04-9813-a3b565d87c83 – dudeNumber4

Odpowiedz

2

Wpisz ponownie zapytanie w składni Lambda, co skróci czas nawet o 3 sekundy (a przynajmniej w przypadku mojego projektu EF).

return _ctx.Parents.Include("Children").AsQueryable<Parent>(); 

i

IQueryable<Parent> qry; // from above 
List<int> ids; // huge list (8500) 
var filtered = qry.Where(p => p.Children.Any(c => ids.Contains(c.ChildId))); 
+0

'Wybierz (s => s)' nic nie robi. Zakończ go po tym, gdzie. – StriplingWarrior

+0

Dobrze ... Dzięki! –

+0

To nie robiło różnicy w moim przypadku. – dudeNumber4

4

Niestety zapytań budowlanych w LINQ podmiotom jest dość ciężkie uderzenie, ale znalazłem to zazwyczaj oszczędza czas, ze względu na zdolność do budowania zapytań z ich składowych elementów przed faktycznie trafiając do bazy danych.

Jest prawdopodobne, że sposób, w jaki implementują metodę Contains, wykorzystuje algorytm, który zakłada, że ​​Contains jest zwykle używany do relatywnie małego zestawu danych. Zgodnie z moimi testami, ilość czasu potrzebnego na identyfikację na liście zaczyna rosnąć o około 8000.

Może to pomóc w rozbiciu zapytania na części. Zgrupuj je w grupy o wielkości 1000 lub mniejszej i połącz szeregiem wyrażeń Where.

var idGroups = ids.GroupBy(i => i/1000); 
var q = Parents.Include("Children").AsQueryable(); 
var newQ = idGroups.Aggregate(q, 
    (s, g) => s.Concat(
        q.Where(w => w.Children.Any(wi => g.Contains(wi.ChildId))))); 

To znacznie przyspiesza rzeczy, ale to nie może być na tyle istotny dla swoich celów, w tym przypadku będziesz musiał uciekać się do procedury przechowywanej. Niestety ten konkretny przypadek użycia nie pasuje do "pudełka" oczekiwanego zachowania Entity Framework. Jeśli twoja lista identyfikatorów mogłaby się zaczynać jako zapytanie z tego samego kontekstu podmiotów, struktura Entity Framework działałaby dobrze.

+0

Wycofano, ale nie oznaczono jako odpowiedzi. Używanie przechowywanych proców jest odpowiedzią, ale nie ma mowy, żebym użył zepsutego rozwiązania zapytania. Po prostu użyję uszkodzonego rozwiązania EF ... – dudeNumber4

+0

Zachęcam cię do rozpoczęcia nagrody lub zaznaczenia odpowiedzi. Nawet jeśli napiszesz swoją własną odpowiedź opartą na procesem zapisanym w pamięci, to FAQ wyraźnie stwierdza, że ​​jest to dopuszczalne.Oczywiście, chciałbym również zwrócić uwagę, że nie tylko odpowiedziałem na pytanie, o które prosiłem, ale także dostarczyłem rozwiązanie, które brzmi, jakbyś chciał z niego skorzystać. – StriplingWarrior

+0

To jest prawdopodobnie najlepsza odpowiedź, którą otrzymasz. Skoro ktoś wychodzi z poprawką do frameworka, to jest odpowiedź. –

Powiązane problemy