【问题标题】:Entity Framework causing Timeout Error实体框架导致超时错误
【发布时间】:2015-04-03 18:27:17
【问题描述】:

我正在使用以下实体框架查询。我知道这里发生了很多事情,但我希望它足够清楚,以便有人能够发现问题。

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
                };

按原样,此查询会生成以下运行时错误:

等待操作超时

如果我将声明 selectedChoiceId 的部分更改为以下内容,错误就会消失:

let selectedChoiceId = 0

任何人都可以看到该代码是如何持续导致超时错误的吗?

(注意:这段代码是一个已经运行了好几年的大型应用程序的一部分。所以我真的不认为这与连接字符串或类似的东西有任何关系。如果我让上面的变化,它始终如一地工作。)

【问题讨论】:

  • 它看起来与 sql-server 相关,而不是 EF 问题。其他人建议更新统计信息serverfault.com/questions/419997/…。也可能是阻塞问题-您可以尝试读取未提交的数据stackoverflow.com/a/24699606/2224701。
  • @VojtěchDohnal:我认为最终错误是在 SQL Server 中发生的。问题实际上是关于会在 SQL Server 中导致此问题的有问题的行。我高度怀疑这是一个阻塞问题。阻塞问题一般取决于其他代码,不会像上面的代码那样一致。
  • 乍一看,我怀疑selectedChoiceId 声明会导致从 EF 向 SQL Server 发送更复杂的子查询,因此自然删除它会更快执行(因此不会超时)。我将附加分析器,捕获生成的 SQL,并调查其估计的执行计划以查看它命中哪些索引以及如何命中。
  • 尝试移动var choice = (from c in li.OriginalPackageOption.CostingLineItems orderby (c.IsIncluded ?? false) ? -2 : (c.IsDefaultItem ?? false) ? -1 : c.Id select (int)c.OriginalPackageOptionChoiceId).FirstOrDefault() : 0,然后使用let selectedChoiceId = choice 我认为子查询应该有问题。
  • @Nilesh:把它移到哪里,为什么会有什么不同?

标签: c# sql-server linq entity-framework


【解决方案1】:

可以通过多种方式简化查询,这应该更容易被数据库引擎优化。

首先,您可以删除一些空检查 (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
}

对于其余的,当然还有通常的嫌疑人。随着数据库容量的增加,更好的索引可能变得更加重要。检查(和修复)数据库碎片也会产生重大影响。

【讨论】:

    【解决方案2】:

    我认为这会给您带来更好的性能,但不确定它是否能解决问题:

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-02-01
      • 1970-01-01
      • 2011-09-08
      • 2021-08-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多