Aiuto necessario per ottimizzare l'estrazione dei dati linq
-
22-07-2019 - |
Domanda
Sto recuperando i dati da tutte e 3 le tabelle contemporaneamente per evitare la latenza della rete. Il recupero dei dati è piuttosto veloce, ma quando eseguo il ciclo tra i risultati viene utilizzato molto tempo
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!!
Soluzione
Perché ti preoccupi di controllare i conteggi prima delle dichiarazioni foreach? Se non ci sono risultati, la foreach finirà immediatamente.
Le tue query in realtà vengono tutte rinviate: verranno eseguite come e quando richiedi i dati. Non dimenticare che la tua query più esterna è una query LINQ to Objects: sta solo restituendo il risultato della chiamata ent.Basket.Where (...). Seleziona (...)
ecc ... che in realtà non esegue la query.
Il tuo piano per eseguire tutte e tre le query in una volta sola non funziona davvero. Tuttavia, chiedendo il conteggio separatamente, potresti effettivamente eseguire ogni query del database due volte, una volta solo ottenendo il conteggio e una volta per i risultati.
Ti consiglio vivamente di sbarazzarti delle " ottimizzazioni " in questo codice che lo rende molto più complicato e più lento rispetto alla semplice scrittura del codice più semplice che puoi.
Non conosco alcun modo per fare in modo che LINQ to SQL (o LINQ to EF) esegua più query in una singola chiamata, ma questo approccio certamente non lo farà.
Un altro suggerimento minore che è irrilevante in questo caso, ma può essere utile in LINQ to Objects - se vuoi scoprire se ci sono dati in una raccolta, usa invece Any ()
di Count () > 0
- in questo modo può fermarsi non appena trova qualcosa.
Altri suggerimenti
Stai usando IEnumerable
nel ciclo foreach. Le implementazioni devono preparare i dati solo quando richiesti. In questo modo, suggerirei che il codice sopra acceda pigramente ai tuoi dati, vale a dire solo quando si enumerano gli elementi (cosa che accade effettivamente quando si chiama Count ()
.)
Metti un System.Diagnostics.Stopwatch
attorno alla chiamata su Count ()
e vedi se ci vuole gran parte del tempo che vedi.
Non posso commentare ulteriormente qui perché non specifichi il tipo di ent
nell'esempio di codice.