C# 实体框架导致超时错误
我正在处理以下实体框架查询。我知道这里发生了很多事情,但我希望有人能够发现这个问题C# 实体框架导致超时错误,c#,sql-server,linq,entity-framework,C#,Sql Server,Linq,Entity Framework,我正在处理以下实体框架查询。我知道这里发生了很多事情,但我希望有人能够发现这个问题 var lineItems = from li in Repository.Query<CostingLineItem>() let cid = (li.ParentCostingPackage != null) ? li.ParentCostingPackage.ParentCostingEvent.ProposalSecti
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
};
有人能看到该代码是如何持续导致超时错误的吗
(注意:这段代码是一个运行了几年的大型应用程序的一部分。因此,我真的不认为这与连接字符串或类似的东西有任何关系。如果我做了上述更改,它将始终如一地工作。)我认为这将给您带来更好的性能,但不确定它是否能解决问题:
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
查询可以通过多种方式简化,这将使数据库引擎更容易进行优化 首先,您可以删除大量空检查(
HasValue
),因为它们在SQL中不相关,但它们会膨胀生成的SQL
其次,我认为涉及selectedChoiceId
的检查可以大大简化。这就是我认为该声明可能的样子:
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
}
来自Repository.Query()中的li
让cid=(li.ParentCostingPackage!=null)?
li.ParentCostingPackage.ParentCostingEvent.ProposalsSection.Proposal.Costing.Id:
li.ParentCostingEvent.ProposalSection.Proposal.Costing.Id
其中cid==costingId&&
li.OriginalProductId.HasValue&&
li.数量>0&&//无空检查
分类。包含(li.OriginalProduct.ClassificationEnumIndex)
让selectedChoiceId=(从li.OriginalPackageOption.CostingLineItems中的c开始)
orderby c.IsIncluded?-2:c.IsDefaultItem?-1:c.Id//无空检查
选择(int)c.OriginalPackageOptionChoiceId).FirstOrDefault()
哪里li.OriginalPackageOptionId.HasValue | | li.OriginalPackageOptionId==selectedChoiceId
让hasProviderAvailable=li.OriginalProductItem.ProductItemVendors.Any(
piv=>piv.ProductPricings.Any(pp=>pp.ProductItemVendor.CompanyId!=null | | pp.ProductItemVendor.HotelId!=null))
选择新的
{
LineItem=li,
ProductItem=li.OriginalProductItem,
产品=li.原始产品,
供应商=li.costinglineitemsvendors,
HasProviderAvailable=HasProviderAvailable
}
至于其他人,当然还有通常的嫌疑犯。随着数据库容量的增加,更好的索引可能变得更加重要。检查(并修复)数据库碎片也会产生重大影响。它看起来与sql server相关,而不是EF问题。其他人建议更新统计数据。也可能是阻塞问题-您可以尝试读取未提交的数据。@VojtěchDohnal:我假设错误最终发生在SQL Server中。问题是,在SQL Server中,哪些行会导致此问题。我高度怀疑这是一个阻塞问题。阻塞问题通常取决于其他代码,并且不会像上面的代码那样一致。第一次查看时,我怀疑
selectedChoiceId
声明会导致从EF向SQL Server发送更复杂的子查询,因此自然删除它会执行得更快(因此不会超时)。我将附加探查器,捕获生成的SQL,并调查其估计的执行计划,以查看它会命中哪些索引以及如何移动。尝试移动var choice=(从li.OriginalPackageOption.CostingLineItems orderby中的c开始)(c.isinclude??false)?-2:(c.IsDefaultItem??false)?-1:c.Id选择(int)c.OriginalPackageOptionChoiceId)。首先Ordefault():0
然后使用let selectedChoiceId=choice
我认为子查询应该有问题。@Nilesh:将其移动到何处,为什么会有任何区别?
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
}