2015-04-03 21 views
5

Sto lavorando con la seguente query Entity Framework. So che c'è molto da fare qui, ma spero che sia abbastanza chiaro che qualcuno potrebbe essere in grado di individuare il problema.Entity Framework che causa un errore di timeout

var lineItems = from li in Repository.Query<CostingLineItem>() 

       let cid = (li.ParentCostingPackage != null) ? 
        li.ParentCostingPackage.ParentCostingEvent.ProposalSection.Proposal.Costing.Id : 
        li.ParentCostingEvent.ProposalSection.Proposal.Costing.Id 

       where cid == costingId && 
        li.OriginalProductId.HasValue && 
        (li.Quantity.HasValue && li.Quantity.Value > 0) && // li.QuantityUnitMultiplier 
        Classifications.Contains(li.OriginalProduct.ClassificationEnumIndex) 

       let selectedChoiceId = li.OriginalPackageOptionId.HasValue ? 
        (from c in li.OriginalPackageOption.CostingLineItems 
         orderby (c.IsIncluded ?? false) ? -2 : (c.IsDefaultItem ?? false) ? -1 : c.Id 
         select (int)c.OriginalPackageOptionChoiceId).FirstOrDefault() : 
        0 

       where selectedChoiceId == 0 || (li.OriginalPackageOptionChoiceId.HasValue && li.OriginalPackageOptionId.Value == selectedChoiceId) 

       let hasProviderAvailable = li.OriginalProductItem.ProductItemVendors.Any(
        piv => piv.ProductPricings.Any(pp => pp.ProductItemVendor.CompanyId != null || pp.ProductItemVendor.HotelId != null)) 

       select new 
       { 
        LineItem = li, 
        ProductItem = li.OriginalProductItem, 
        Product = li.OriginalProduct, 
        Vendors = li.CostingLineItemVendors, 
        HasProviderAvailable = hasProviderAvailable 
       }; 

Come è, questa query genera il seguente errore di runtime:

The wait operation timed out

Se cambio la sezione che dichiara selectedChoiceId al seguente, l'errore va via:

let selectedChoiceId = 0 

Qualcuno può vedere come questo codice causa costantemente un errore di timeout?

(Nota: questo codice fa parte di una grande applicazione in esecuzione da diversi anni, quindi non credo che questo abbia nulla a che fare con la stringa di connessione o qualcosa di simile. sopra, funziona sempre)

+0

Sembra piuttosto correlato a SQL Server rispetto al problema EF. Altri raccomandano l'aggiornamento delle statistiche http://serverfault.com/questions/419997/the-wait-operation-timed-out-when-running-sql-server-in-hyper-v. Potrebbe anche esserci un problema di blocco: puoi provare a leggere i dati non inviati http://stackoverflow.com/a/24699606/2224701. –

+0

@ VojtěchDohnal: ho assunto che, in definitiva, l'errore si stesse verificando all'interno di SQL Server. La domanda è in realtà ciò che riguarda le righe in questione che causerebbe questo problema in SQL Server. Dubito fortemente che si tratti di un problema di blocco. I problemi di blocco generale dipendono da un altro codice e non sarebbero coerenti come il codice precedente. –

+0

Al primo sguardo sospetto che il 'selectedChoiceId' risultati dichiarazione in un subquery più complicato inviati da EF per SQL Server, eliminando così naturalmente esegue più veloce (quindi nessun time out). Allego il profiler, acquisisco l'SQL generato e analizzo il suo piano di esecuzione stimato per vedere quali indici colpisce e come. –

risposta

0

la query può essere semplificato in un certo numero di modi, che dovrebbe rendere più facile l'ottimizzazione tramite il motore del database.

In primo luogo, è possibile rimuovere un numero di assegni null (HasValue), perché non sono rilevanti in SQL, ma gonfiano l'SQL generato.

secondo luogo, ritengo questo controllo coinvolge selectedChoiceId può essere notevolmente semplificata. Questo è ciò che penso che la dichiarazione potrebbe sembrare:

from li in Repository.Query<CostingLineItem>() 

let cid = (li.ParentCostingPackage != null) ? 
    li.ParentCostingPackage.ParentCostingEvent.ProposalSection.Proposal.Costing.Id : 
    li.ParentCostingEvent.ProposalSection.Proposal.Costing.Id 

where cid == costingId && 
    li.OriginalProductId.HasValue && 
    li.Quantity > 0 && // no null check 
    Classifications.Contains(li.OriginalProduct.ClassificationEnumIndex) 

let selectedChoiceId = (from c in li.OriginalPackageOption.CostingLineItems 
     orderby c.IsIncluded ? -2 : c.IsDefaultItem ? -1 : c.Id // no null checks 
     select (int)c.OriginalPackageOptionChoiceId).FirstOrDefault() 

where !li.OriginalPackageOptionId.HasValue || li.OriginalPackageOptionId == selectedChoiceId 

let hasProviderAvailable = li.OriginalProductItem.ProductItemVendors.Any(
    piv => piv.ProductPricings.Any(pp => pp.ProductItemVendor.CompanyId != null || pp.ProductItemVendor.HotelId != null)) 

select new 
{ 
    LineItem = li, 
    ProductItem = li.OriginalProductItem, 
    Product = li.OriginalProduct, 
    Vendors = li.CostingLineItemVendors, 
    HasProviderAvailable = hasProviderAvailable 
} 

Per il resto, naturalmente ci sono i soliti sospetti. Gli indici migliori possono diventare più importanti all'aumentare del volume del database. Anche il controllo (e la correzione) della frammentazione del database può avere un impatto significativo.

0

penso che questo vi darà una migliore performance, ma non sono sicuro se che sarà risolvere il problema:.

let selectedChoiceId = li.OriginalPackageOptionId.HasValue 
    ? (from c in li.OriginalPackageOption.CostingLineItems 
     let cOrder = (c.IsIncluded ?? false) ? -2 : (c.IsDefaultItem ?? false) ? -1 : c.Id 
     orderby cOrder 
     select (int) c.OriginalPackageOptionChoiceId).FirstOrDefault() 
    : 0 
Problemi correlati