2011-09-12 12 views
6

Jako przykład podajemy następujące zapytanie LINQ. Proszę nie komentować samego kodu, ponieważ właśnie go wpisałem, aby pomóc w rozwiązaniu tego problemu.Duże zapytanie grupowania LINQ, co się dzieje za kulisami

Następujące zapytanie LINQ używa "grupy według" i oblicza informacje podsumowujące. Jak widać, istnieje wiele obliczeń, które są wykonywane na danych, ale jak skuteczne jest LINQ za kulisami.

var NinjasGrouped = (from ninja in Ninjas 
    group pos by new { pos.NinjaClan, pos.NinjaRank } 
    into con 
    select new NinjaGroupSummary 
    { 
     NinjaClan = con.Key.NinjaClan, 
     NinjaRank = con.Key.NinjaRank, 
     NumberOfShoes = con.Sum(x => x.Shoes), 
     MaxNinjaAge = con.Max(x => x.NinjaAge), 
     MinNinjaAge = con.Min(x => x.NinjaAge), 
     ComplicatedCalculation = con.Sum(x => x.NinjaGrade) != 0 
     ? con.Sum(x => x.NinjaRedBloodCellCount)/con.Sum(x => x.NinjaDoctorVisits) 
     : 0, 
    ListOfNinjas = con.ToList() 
    }).ToList(); 
  1. Ile razy jest lista „Ninjas” jest powtórzyć w ciągu w celu obliczenia każdej wartości?
  2. Czy szybsze byłoby użycie pętli foreach, aby przyspieszyć wykonanie takiego zapytania?
  3. Dodanie ".AsParallel()" po Ninjas spowoduje poprawę wydajności?
  4. Czy istnieje lepszy sposób obliczania letniej informacji dla listy?

Każda rada jest doceniana, ponieważ używamy tego rodzaju kodu w całym naszym oprogramowaniu i naprawdę chciałbym lepiej zrozumieć, co LINQ robi pod maską (że tak powiem). Być może istnieje lepszy sposób?

+1

+1 dla ninja. –

+0

Ważne jest, aby wiedzieć, czy 'Ninjas' jest' IEnumerable' lub 'IQueryable'. Jeśli były, zostanie wyliczony dokładnie jeden raz. Jeśli to ostatnie, nie ma wyliczenia, o którym można by mówić; zapytanie jest kompilowane bezpośrednio do, na przykład, SQL; grupowanie jest wykonywane przez DBMS, a jedyną rzeczą wymienioną w C# jest zestaw wyników. –

+0

"Ninjas" jest na liście pamięci, IEnumerable. – Belinda

Odpowiedz

6

Zakładając, że jest to LINQ Obiekty zapytania:

  • Ninjas tylko powtarzana na raz; grupy są wbudowane w wewnętrzne listy konkretnych elementów, które następnie są iterowane wielokrotnie (jeden raz na agregację).
  • Użycie pętli prawie na pewno nie przyspieszyłoby pracy - możesz skorzystać ze spójności pamięci podręcznej nieco więcej (ponieważ za każdym razem, gdy wykonujesz iterację w grupie, prawdopodobnie będziesz musiał pobrać dane z pamięci podręcznej lub pamięci głównej wyższego poziomu), ale bardzo wątpię, że byłoby to znaczące. Wzrost bólu w jego wdrażaniu prawdopodobnie byłoby być znaczące, choć :)
  • Korzystanie AsParallelpotęga przyspieszyć - wygląda dość łatwo parallelizable. Warto wypróbować ...
  • Nie ma lepszego sposobu na LINQ do obiektów, szczerze mówiąc. Byłoby miło móc wykonać agregację w trakcie zgrupowania, a rozszerzenia reaktywne pozwoliłyby na zrobienie czegoś podobnego, ale na razie jest to prawdopodobnie najprostsze podejście.

Czasami warto spojrzeć na GroupBy post in my Edulinq blog series więcej szczegółów na możliwym realizacji.

+1

Dzięki Jon, to jest kwerenda LINQ to Objects. Czy możesz rozwinąć swój komentarz "Używanie pętli foreach prawie na pewno by nie przyspieszyło", nie widzę, jak to jest prawda, jeśli wewnętrzne listy konkretnych są powtarzane (potencjalnie) wiele razy? – Belinda

+0

@Bindinda: Cóż, przetwarzasz tę samą ilość danych - po prostu śledzisz sprawy nieco inaczej. Sądzę, że skorzystasz trochę ze spójności pamięci podręcznej - ale bardzo wątpię, że byłaby znacząca. Zmodyfikuje, aby było bardziej zrozumiałe. –

+0

@JonSkeet Czy jedna pętla nad 'con' nie przyspieszyłaby rzeczy, ponieważ byłaby w stanie wyliczyć wszystkie wartości zagregowane za jednym razem? (Teraz każdy agregat musi samodzielnie "konwertować") – Magnus

Powiązane problemy