Aide nécessaire pour optimiser l'extraction de données linq
-
22-07-2019 - |
Question
Je récupère les données des 3 tables en même temps pour éviter la latence du réseau. La récupération des données est assez rapide, mais lorsque je parcours les résultats, cela prend beaucoup de temps
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!!
La solution
Pourquoi prenez-vous la peine de vérifier les comptes avant les déclarations Foreach? S'il n'y a pas de résultat, le foreach finira juste immédiatement.
Vos requêtes sont en fait toutes différées - elles seront exécutées au fur et à mesure que vous demanderez les données. N'oubliez pas que votre requête la plus externe est une requête LINQ to Objects: elle ne fait que renvoyer le résultat de l'appel de ent.Basket.Where (...). Sélectionnez (...)
etc ... qui n'exécute pas réellement la requête.
Votre plan pour traiter les trois requêtes en une fois ne fonctionne pas. Cependant, en demandant le nombre séparément, vous exécuterez peut-être chaque requête de base de données deux fois, une fois pour obtenir le nombre et une fois pour les résultats.
Je vous suggère fortement de vous débarrasser des "optimisations". dans ce code, ce qui le rend beaucoup plus compliqué et plus lent que d'écrire simplement le code le plus simple possible.
Je ne connais aucun moyen d'obtenir que LINQ to SQL (ou LINQ to EF) exécute plusieurs requêtes en un seul appel - mais cette approche ne le fera certainement pas.
Un autre indice mineur qui n'est pas pertinent dans ce cas, mais qui peut être utile dans LINQ to Objects - si vous voulez savoir s'il existe des données dans une collection, utilisez simplement Any ()
. de Compter () > 0
- de cette façon, il peut s'arrêter dès qu'il trouve quoi que ce soit.
Autres conseils
Vous utilisez IEnumerable
dans la boucle foreach. Les implémentations doivent seulement préparer les données à la demande. De cette façon, je suggérerais que le code ci-dessus accède paresseusement à vos données, c'est-à-dire uniquement lorsque vous énumérez les éléments (ce qui se produit lorsque vous appelez Count ()
.)
Placez un System.Diagnostics.Stopwatch
autour de l'appel à Count ()
et voyez si cela prend la majeure partie du temps que vous voyez.
Je ne peux pas commenter davantage ici car vous ne spécifiez pas le type de ent
dans votre exemple de code.