2012-04-04 24 views
5

¿Cuál sería la mejor manera de obtener todos los productos en todas las categorías secundarias de una categoría principal seleccionada? Intentando obtener 10000 productos en aproximadamente 80 categorías de niños, pero este método es demasiado lento. ¿Alguna sugerencia? usando C# y LINQ to SQLLinq a SQL C# Obtenga productos en todas las categorías secundarias/secundarias demasiado lentas

//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 aproximadamente 6 segundos para devolver resultados

+1

¿tiene los índices apropiados? es este marco de entidad o linq a sql? –

+0

¿está permitido cambiar CategoryID de varchar a int? –

+0

sí, los índices están ahí. Es Linq a SQL. CategoryID es int pero acepta nulo. El ID principal de las categorías principales es nulo THanks – vts

Respuesta

3

¿Cuál es la diferencia entre

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

y

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

?

Quizás mi esquema sea diferente, pero cuando intento esto con Linq2Sql parece devolver los mismos resultados, pero este último devuelve los resultados en un solo hit de base de datos, mientras que el primero emite varias solicitudes. (Si la cantidad de productos devueltos es 10000, estaría haciendo 10001 solicitudes de base de datos).

+0

¡Increíble! Esto funcionó muy bien. en menos de 1 segundo. Gracias – vts

+0

¿Por qué es que .ToList(); lo hace funcionar rápido pero sin él carga muy lento? – vts

+0

El .ToList() obliga a los productos a recuperarse en esa etapa y eso es una confusión y consulta directa. La agrupación se realiza en la memoria. Sin .ToList(), le está pidiendo a Linq2SQL que haga tanto la agrupación como la selección, y no parece hacer un gran trabajo. Tenga en cuenta que si solo deseara la cantidad de productos por categoría (y no los detalles de los productos), entonces .ToList() ralentizaría las cosas, ya que sería malo devolver los detalles de los 10000 productos y luego agruparlos y contarlos, mientras que sin .ToList(), pedirá al sql que agrupe y cuente. – sgmoore

2

Sobre la base de las estadísticas & código proporcionado, debe guardar 3 segundos mediante la eliminación de esta línea:

if (cats.Count() > 0) 

... porque dobla las enumeraciones (y dado que eso significa que estás duplicando tus llamadas a la base de datos, es totalmente malo) y es bastante inútil ya que no hay nada después de eso que fallaría si Count == 0.

Si está accediendo a un servidor MS SQL, el generador de perfiles que proporcionan es su amigo aquí porque es probable que vea una base de datos adicional.

+4

Si necesitan verificar, deberían usar 'cats.Any()' o deshacerse de él ya que el 'foreach' ni siquiera formará un bucle. – user7116

+0

Imagino que 'Any' también daría lugar a una base de datos adicional aquí, pero es un buen punto. –

+0

Gracias. Desafortunada Eso no ayudó mucho. Creo que el problema es con g.Any (x => catsChildList.Contains (Convert.ToInt32 (x.CategoryID). Tener que verificar cada producto con la lista. – vts

0

a. La siguiente línea de código es una sustitución de la expresión lambda de la primera línea a través del método 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); 

Pero incluso esto haría la recursión, pero se haría internamente. Por favor revisa eso. Por supuesto, es un código no probado, solo basado en sus objetos.

b. Otros piensan que puedes intentarlo, puedes intentar reemplazar db2.tbl_cart_categories por db2.tbl_cart_categories.AsParallel(). No estoy seguro de cómo se comporta el contexto del objeto/contexto de datos con esto. Pero db2 no es un objeto de contexto, entonces estoy seguro de que mejoraría el rendimiento.

0

En primer lugar, aunque no especifique, supongo que está utilizando Linq a Sql. Por favor actualice su pregunta para incluir esa información.

Comience añadiendo algunos perfiles básicos. ¿Qué consulta tarda más en ejecutarse?

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

Esto es definitivamente sospechoso. Si catsChildList tiene muchos valores, podría estar generando una enorme cláusula IN, que siempre se ejecutará lentamente. Puede verificarlo comprobando la instrucción SQL real que se está ejecutando.

La verdad es que el recorrido de jerarquías recursivas como este nunca va a ser eficiente cuando intenta realizar cada iteración en su aplicación. Obtendrá un rendimiento mucho mejor utilizando un procedimiento almacenado.

+0

Es Ling a SQL. Sí, hay alrededor de 80 categorías de niños por lo tiene sentido que ese sea el problema. ¿Cómo se vería el procedimiento de la tienda en comparación con la instrucción sql que se está ejecutando? ¿Hay una mejor manera de hacerlo con una sp? – vts

+0

Después de crear un único procedimiento almacenado, puede arrastrarlo a su diagrama de modelo de entidad y se mostrará en la lista (no en la vista de diseño). Desde allí, puede llamar directamente al SP y devolver una entidad que represente la salida de su columna desde el SP. –

Cuestiones relacionadas