2012-04-04 15 views
5

Quale sarebbe il modo migliore per ottenere tutti i prodotti in tutte le categorie secondarie di una categoria principale selezionata? Cercando di ottenere 10000 prodotti in circa 80 categorie figlio, ma questo metodo è troppo lento. Eventuali suggerimenti? utilizzando C# e LINQ to SQLDa Linq a SQL C# Ottieni prodotti in tutti i child/sub child Categorie troppo lenti

//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))) 

dura circa 6 secondi per restituire i risultati

+1

hai gli indici appropriati? è questa entità framework o linq to sql? –

+0

sei autorizzato a cambiare IDCase da varchar a int? –

+0

yeah Gli indici ci sono. È Linq to SQL. ID della categoria è int ma accetta null. L'ID genitore delle categorie principali è nullo THanks – vts

risposta

3

Qual è la differenza tra

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 
    ); 

e

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); 

?

Forse il mio schema è diverso, ma quando provo questo con Linq2Sql sembra restituire gli stessi risultati, ma quest'ultimo restituisce i risultati in un solo colpo di database, mentre il primo emette più richieste. (Se il numero di prodotti restituiti è 10000, farebbe 10001 richieste di database).

+0

Incredibile! Funzionava alla grande. in meno di 1 secondo Grazie – vts

+0

Perché è così .ToList(); lo fa girare veloce ma senza di esso si carica molto lentamente? – vts

+0

Il .ToList() forza il recupero dei prodotti in quella fase e questo è un falso y query semplice. Il raggruppamento viene quindi eseguito in memoria. Senza la .ToList(), stai chiedendo a Linq2SQL di eseguire sia il raggruppamento che la selezione, e non sembra che faccia un ottimo lavoro. Nota, se si desidera solo il numero di prodotti per categoria (e non i dettagli dei prodotti), allora .ToList() rallenterebbe le cose poiché significherebbe restituire i dettagli dei prodotti 10000 e quindi raggrupparli e contarli, mentre senza .ToList(), chiederà allo sql di raggrupparsi e contarli. – sgmoore

2

Sulla base delle statistiche & codice fornito, è consigliabile salvare 3 secondi dalla rimozione di questa linea:

if (cats.Count() > 0) 

... perché raddoppia le enumerazioni (e dato che significa che stai raddoppiando le tue chiamate di database, è completamente fuori luogo) e è praticamente inutile dato che non c'è niente dopo che si bloccherebbe se Conteggio == 0.

Se si sta colpendo un MS SQL Server, il Profiler che forniscono è tuo amico qui perché probabilmente si vedrà un colpo di database in più.

+4

Se hanno bisogno di controllare, dovrebbero usare 'cats.Any()' o sbarazzarsi di esso poiché 'foreach' non eseguirà il ciclo. – user7116

+0

Immagino che "Any" comporterà anche un hit extra per il database qui, ma buon punto. –

+0

Grazie. Sfortuna che non ha aiutato molto Credo che il problema sia con g.Any (x => catsChildList.Contains (Convert.ToInt32 (x.CategoryID). Dovendo controllare ogni prodotto contro la lista – vts

0

a. La seguente riga di codice è una sostituzione di espressione lambda della prima riga attraverso il metodo 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); 

Ma anche questo avrebbe fatto la ricorsione, ma sarebbe stato fatto internamente. Si prega di controllare. Ovviamente è un codice non testato, basato solo sui tuoi oggetti.

b. Altri pensano che puoi provare, puoi provare a sostituire db2.tbl_cart_categories in db2.tbl_cart_categories.AsParallel(). Non sono sicuro di come si comportano il contesto oggetto/contesto dati con questo. Ma db2 non è un oggetto di contesto, quindi sono sicuro che migliorerebbe le prestazioni.

0

Prima di tutto, anche se non si specifica, presumo che si stia utilizzando Linq su Sql. Si prega di aggiornare la domanda per includere tali informazioni.

Iniziare aggiungendo alcuni profili di base. Quale query impiega più tempo per essere eseguita?

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

Questo è decisamente sospetto. Se catsChildList ha molti valori, potresti potenzialmente generare un'enorme clausola IN, che verrà sempre eseguita lentamente. È possibile verificarlo controllando l'effettiva istruzione SQL in esecuzione.

La verità è che l'attraversamento gerarchico ricorsivo come questo non sarà mai efficiente quando si tenta di eseguire ogni iterazione nella propria applicazione. Otterrai prestazioni molto migliori usando una stored procedure.

+0

È Ling a SQL Sì, ci sono circa 80 categorie di bambini è logico che sia questo il problema: come apparirebbe la procedura del negozio rispetto all'istruzione sql che viene eseguita? c'è un modo migliore per farlo con una sp? grazie? – vts

+0

Dopo aver creato una singola stored procedure, puoi trascinarla su al tuo Diagramma Modello Entity e verrà visualizzato nell'elenco (non nella vista di progettazione) .Dal lì puoi chiamare direttamente l'SP e restituire un'entità che ripete l'output della colonna dall'SP. –

Problemi correlati