2012-04-04 11 views
5

Jaki byłby najlepszy sposób uzyskania wszystkich produktów we wszystkich kategoriach podrzędnych wybranej kategorii głównej? Próbujesz uzyskać 10000 produktów w około 80 kategoriach dzieci, ale ta metoda jest zbyt powolna. Jakieś sugestie? przy użyciu C# i LINQ to SQLLinq do SQL C# Uzyskaj produkty we wszystkich kategoriach dziecko/podrzędny Kategorie zbyt wolne

//list for the child categories 
private List<int> catsChildList = new List<int>(); 

GetChildCats(123); 

//get all the child categories of main category '123' 

private void GetChildCats(int _parentCat) 
{ 
    var cats = (from c in db2.tbl_cart_categories 
       where c.ParentID == _parentCat 
       select new { c.CategoryID }); 
    if (cats.Count() > 0) 
    { 
     foreach (var cat in cats) 
     { 
      int _cat = Convert.ToInt32(cat.CategoryID); 
      catsChildList.Add(_cat); 
      GetChildCats(_cat); 
     } 
    } 
} 

//Get the products 
var products = (from p in db2.products_infos 
      where p.IsEnabled == true 
      group p by p.ProdID 
      into g where g.Any(x => catsChildList.Contains(Convert.ToInt32(x.CategoryID))) 

trwa około 6 sekund, aby powrócić wyników

+1

Czy masz odpowiednie indeksy? to jest struktura encji lub linq do sql? –

+0

Czy możesz zmienić CategoryID z varchar na int? –

+0

tak Indeksy tam są. To Linq do SQL. CategoryID jest int, ale akceptuje wartość null. Główne kategorie ID rodzica jest nieważne Pozdrawiam – vts

Odpowiedz

3

Jaka jest różnica między

var products = 
    (
    from p in db2.products_infos 
    where p.IsEnabled == true 
    group p by p.ProdID 
    into g where g.Any(x => catsChildList.Contains(Convert.ToInt32(x.CategoryID))) 
    select g 
    ); 

i

var tmpList = 
    (
    from p in db2.products_infos 
    where p.IsEnabled == true 
      && catsChildList.Contains(Convert.ToInt32(p.CategoryID))) 
    select p 
    ).ToList(); 

var products = 
    (from r in tmpList group p by r.ProdID into g select g); 

?

Może mój schemat jest inny, ale kiedy próbuję tego z Linq2Sql, wydaje się, że zwraca te same wyniki, ale drugi zwraca wyniki w jednym uderzeniu bazy danych, podczas gdy pierwszy wydaje wiele żądań. (Jeśli liczba zwróconych produktów wynosi 10000, to wykona 10001 żądań bazy danych).

+0

To zadziałało. w mniej niż 1 sekundę Dziękujemy – vts

+0

Dlaczego to jest .ToList(); sprawia, że ​​działa szybko, ale bez niego ładuje się bardzo wolno? – vts

+0

.ToList() zmusza produkty do pobrania na tym etapie i to jest fairl y proste zapytanie. Grupowanie jest następnie wykonywane w pamięci. Bez .ToList(), pytasz Linq2SQL, aby wykonać zarówno grupowanie, jak i wybór i nie wydaje się, żeby to było świetną robotą. Uwaga: gdybyś chciał tylko liczby produktów na kategorię (a nie szczegółów produktu), to .ToList() spowolniłoby działanie, ponieważ oznaczałoby zwrócenie szczegółów 10000 produktów, a następnie ich zgrupowanie i zliczenie, bez .ToList(), poprosi sql, aby je zgrupować i policzyć. – sgmoore

2

Opierając się na statystykach kod & usług, należy zapisać 3 sekundy przez usunięcie tej linii:

if (cats.Count() > 0) 

... ponieważ podwaja wyliczenia (i oznacza to, że podwajasz połączenia z bazami danych, to jest źle zera) i jest prawie bezsensowne, ponieważ nie ma po nim nic takiego zawiesiłoby się, gdyby Count == 0.

Jeśli trafiasz na serwer MS SQL Server, dostarczony przez niego profil jest twoim przyjacielem, ponieważ prawdopodobnie zobaczysz dodatkowe trafienie bazy danych.

+4

Jeśli muszą sprawdzić, powinny użyć 'cats.Any()' lub pozbyć się go, ponieważ 'foreach' nie będzie nawet pętli. – user7116

+0

Wyobrażam sobie, że "Any" spowoduje również dodatkowe uderzenie bazy danych, ale dobry punkt. –

+0

Dziękuję. Niefortunalty To niewiele pomogło. Wierzę, że problem jest z g.Any (x => catsChildList.Contains (Convert.ToInt32 (x.CategoryID) .Musimy sprawdzić każdy produkt z listy – vts

0

a. Poniższy wiersz kodu jest zamiennikiem wyrażenia lambda pierwszego wiersza za pomocą metody GetChildCats().

var findCatList = (List<int> parent) => {   
    from c in db2.tbl_cart_categories 
      where & c.ParentID == _parentCat 
      select (db2.tbl_cart_categories.Any(cat=> cat.ParentID == c.CategoryID) ? 
       findCatList(c.CategoryID) 
       :new { c.CategoryID }      
       )} 

var catList = findCatList(123); 

Ale nawet to wykonałoby rekursję, ale zostanie wykonane wewnętrznie. Proszę to sprawdzić. Oczywiście jest to nietestowany kod, oparty tylko na twoich obiektach.

b. Inni uważają, że możesz spróbować, możesz spróbować zastąpić db2.tbl_cart_categories do db2.tbl_cart_categories.AsParallel(). Nie jestem pewien, jak zachowuje się kontekst obiektu/kontekst danych. Ale db2 nie jest obiektem kontekstowym, więc jestem pewien, że byłby to lepszy wynik.

0

Po pierwsze, mimo że nie określono, zakładam, że używasz Linq do Sql. Zaktualizuj swoje pytanie, aby uwzględnić te informacje.

Zacznij od dodania podstawowych profilów. Które zapytanie trwa najdłużej?

g.Any(x => catsChildList.Contains(Convert.ToInt32(x.CategoryID))) 

Jest to zdecydowanie podejrzane. Jeśli catsChildList ma wiele wartości, potencjalnie można wygenerować ogromną klauzulę IN, która zawsze będzie działała powoli. Możesz to sprawdzić, sprawdzając faktyczną instrukcję SQL, która jest uruchamiana.

Prawda jest taka, że ​​cykliczna rekurencyjna konwersja nigdy nie będzie skuteczna, gdy próbujesz wykonać każdą iterację w aplikacji. Otrzymasz znacznie lepszą wydajność przy użyciu procedury przechowywanej.

+0

Jest Ling do SQL.Tak jest około 80 kategorii dzieci tak ma to sens, że to jest problem. Jak wyglądałaby procedura sklepu w porównaniu do instrukcji sql, która jest uruchamiana? jest lepszy sposób na zrobienie tego za pomocą sp? dziękuję – vts

+0

Po utworzeniu pojedynczej procedury przechowywanej można ją przeciągnąć na do diagramu modelu jednostki i pojawi się na liście (nie w widoku projektu), a stamtąd można bezpośrednio wywołać SP i zwrócić obiekt, który ponownie wyświetli dane wyjściowe kolumny z SP –

Powiązane problemy