【问题标题】:Optimizing A LINQ To Objects Query优化 LINQ To Objects 查询
【发布时间】:2012-10-22 15:11:00
【问题描述】:

我正在尝试优化以下 LINQ 查询以提高其速度性能。它正在搜索的对象数量可能达到数万。

var lQuery = from o in oEvents
where (o.oSalesEvent != null && o.oSalesEvent.OccurDate < oCalcMgr.OccurDate && (
                (oCalcMgr.InclTransTypes == Definitions.TransactionTypes.SalesAll) ?
                   (o.oSalesEvent.EventStateID == ApprovedID || o.oSalesEvent.EventStateID == PendingID) : 
                   o.oSalesEvent.EventStateID == ApprovedID)) &&
      ((oCalcMgr.InclTransTypes == Definitions.TransactionTypes.SalesAll) ? 
                (o.oSalesMan.oEmployment.EventStateID == ApprovedID || o.oSalesMan.oEmployment.EventStateID == PendingID) : 
                 o.oSalesMan.oEmployment.EventStateID == ApprovedID)
select new { SaleAmount = o.SaleAmount.GetValueOrDefault(), CompanyID = o.oSalesEvent.CompanyID };

查询基本上是说,给我某个日期之前发生的所有销售事件的销售额和公司 ID。销售活动的状态和推销员的就业状态应始终为“已批准”,或者如果指定,它们也可以为“待定”。

如您所见,有一个日期比较和几个整数比较。使用哪个整数比较取决于属性是否匹配某个 Enum 值。

我对如何进行优化有一些自己的想法,但我想听听其他人的想法,他们可能对 LINQ 如何在幕后翻译此查询有更深入的了解。

谢谢

【问题讨论】:

  • 在使某些东西变得更快之前,您需要首先了解为什么它现在还不够快。我在您的问题中没有看到任何类型的性能分析,因此无法回答这个问题。关于这个查询需要修复的是什么?如果你不能回答,那你怎么知道有没有更快的答案?
  • 看起来where 子句的后半部分独立于o,因此可以从查询中删除。
  • 没错。 ied 是什么?真的,你名字里的os 是怎么回事?
  • 我不会优化性能,而是从优化可读性开始。创建封装复杂性的方法以避免这种可怕的查询。第一眼没人会明白你在做什么。
  • 您可能希望调整 SO 上的用户 的可读性,因此我们可能更愿意回答您的问题。好处是之后您将拥有更多可读的源代码,供您和需要维护它的任何人使用。

标签: c# .net performance linq optimization


【解决方案1】:

在我看来,您最大的挑战是您在 Linq 语句中执行多个条件检查,这将花费大量时间。 在 oEvents 中创建一个新属性怎么样 - 说“IsEligable”并在其他变量的 Set 语句中设置它的值(比在 Linq 中不断重新查询每个变量要快得多)。

然后,当您到达这部分代码时,您可以将 Linq 更新为以下内容:

var lQuery = from o in oEvents
where (o.oSalesEvent != null && o.oSalesEvent.OccurDate < oCalcMgr.OccurDate && o.IsEligable == True)
select new { SaleAmount = o.SaleAmount.GetValueOrDefault(), CompanyID = o.oSalesEvent.CompanyID };

...我猜这会加快执行速度,但只是一个想法...

【讨论】:

  • 您好约翰,感谢您的回答。我同意,缓存状态将提高性能。不幸的是,如果我创建了 IsEligible 属性,我将不得不将其设为动态属性,以便进行动态检查。这是因为状态可以在运行时改变。一旦我通过动态制作它,它基本上与原始相同,因为重新查询仍在发生。不过,我感谢您的帮助!
【解决方案2】:

这既可以提高可读性,也可以加快速度,但请尝试一下:

var lQueryTemp = from o in oEvents
where (o.oSalesEvent != null && o.oSalesEvent.OccurDate < oCalcMgr.OccurDate)

if (oCalcMgr.InclTransTypes == Definitions.TransactionTypes.SalesAll)
{
  lQueryTemp = from o in lQueryTemp
        where (o.oSalesEvent.EventStateID == ApprovedID || o.oSalesEvent.EventStateID == PendingID) &&
      (o.oSalesMan.oEmployment.EventStateID == ApprovedID || o.oSalesMan.oEmployment.EventStateID == PendingID);
}
else
{
  lQueryTemp = from o in lQueryTemp
        where (o.oSalesEvent.EventStateID == ApprovedID &&  o.oSalesMan.oEmployment.EventStateID == ApprovedID);
}

var lQuery = from o in lQueryTemp
select new { SaleAmount = o.SaleAmount.GetValueOrDefault(), CompanyID = o.oSalesEvent.CompanyID };

这可能会通过提取oCalcMgr.InclTransTypes 的两个检查来加快它的速度,这对于此查询而言实际上是一个常量。

【讨论】:

  • 谢谢鲍勃森。我最初是从不太相似的东西开始的。然后我开始尝试将它带入一个 LINQ 查询中,希望这样可能会减少循环。不过,我的原始代码确实与您的代码有所不同,因此我按照您的方式实现了它。我双向运行了 5 次。不幸的是,这种方式的执行速度实际上稍微慢了一点(平均慢了 0.21 秒)。差异很小,但仍然没有解决。不过还是谢谢!
猜你喜欢
  • 2011-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多