Ayuda necesaria para optimizar la extracción de datos linq
-
22-07-2019 - |
Pregunta
Estoy obteniendo datos de las 3 tablas a la vez para evitar la latencia de la red. Obtener los datos es bastante rápido, pero cuando paso por los resultados se usa mucho tiempo
Int32[] arr = { 1 };
var query = from a in arr
select new
{
Basket = from b in ent.Basket
where b.SUPERBASKETID == parentId
select new
{
Basket = b,
ObjectTypeId = 0,
firstObjectId = "-1",
},
BasketImage = from b in ent.Image
where b.BASKETID == parentId
select new
{
Image = b,
ObjectTypeId = 1,
CheckedOutBy = b.CHECKEDOUTBY,
firstObjectId = b.FIRSTOBJECTID,
ParentBasket = (from parentBasket in ent.Basket
where parentBasket.ID == b.BASKETID
select parentBasket).ToList()[0],
},
BasketFile = from b in ent.BasketFile
where b.BASKETID == parentId
select new
{
BasketFile = b,
ObjectTypeId = 2,
CheckedOutBy = b.CHECKEDOUTBY,
firstObjectId = b.FIRSTOBJECTID,
ParentBasket = (from parentBasket in ent.Basket
where parentBasket.ID == b.BASKETID
select parentBasket),
}
};
//Exception handling
var mixedElements = query.First();
ICollection<BasketItem> basketItems = new Collection<BasketItem>();
//Here 15 millis has been used
//only 6 elements were found
if (mixedElements.Basket.Count() > 0)
{
foreach (var mixedBasket in mixedElements.Basket){}
}
if (mixedElements.BasketFile.Count() > 0)
{
foreach (var mixedBasketFile in mixedElements.BasketFile){}
}
if (mixedElements.BasketImage.Count() > 0)
{
foreach (var mixedBasketImage in mixedElements.BasketImage){}
}
//the empty loops takes 811 millis!!
Solución
¿Por qué te molestas en comprobar los recuentos antes de las declaraciones foreach? Si no hay resultados, el foreach terminará inmediatamente.
En realidad, todas sus consultas se aplazan; se ejecutarán cuando solicite los datos. No olvide que su consulta más externa es una consulta LINQ to Objects: solo devuelve el resultado de llamar a ent.Basket.Where (...). Seleccione (...)
etc. que en realidad no ejecuta la consulta.
Su plan para hacer las tres consultas de una vez no está funcionando realmente. Sin embargo, al solicitar el recuento por separado, en realidad puede estar ejecutando cada consulta de base de datos dos veces, una vez solo obteniendo el recuento y una vez por los resultados.
Le sugiero que elimine las "optimizaciones". en este código, que lo hacen mucho más complicado y más lento que simplemente escribir el código más simple que pueda.
No conozco ninguna forma de hacer que LINQ to SQL (o LINQ to EF) ejecute múltiples consultas en una sola llamada, pero este enfoque ciertamente no lo hará.
Otra sugerencia menor que es irrelevante en este caso, pero que puede ser útil en LINQ to Objects: si desea averiguar si hay datos en una colección, use Any ()
en su lugar de Count () > 0
- de esa manera puede detenerse tan pronto como se encuentre algo.
Otros consejos
Estás usando IEnumerable
en el bucle foreach. Las implementaciones solo tienen que preparar los datos cuando se solicitan. De esta manera, sugeriría que el código anterior esté accediendo a sus datos de manera perezosa, es decir, solo cuando enumera los elementos (lo que realmente sucede cuando llama a Count ()
.)
Coloque un System.Diagnostics.Stopwatch
alrededor de la llamada a Count ()
y vea si eso toma la mayor parte del tiempo que está viendo.
No puedo hacer más comentarios aquí porque no especificas el tipo de ent
en tu muestra de código.