优化或“调整”LINQ表达式的最佳方法是什么?

时间:2009-03-18 14:31:54

标签: linq optimization query-optimization metrics

在构造LINQ表达式时(对我来说,linq到对象)有很多方法可以完成某些事情,有些方法比其他方法更好,更好,更有效。

  • 有没有一种好方法可以“调整”或优化这些表达式?
  • 人们使用什么基本指标以及如何收集它们?
  • 有没有办法获得“总迭代次数”或其他一些指标,你可以“知道”更低意味着更好吗?

修改

感谢Richard / Jon的回答。

我真正想要的是为LINQ表达式获取一个简单的Operation Count“OCount”的方法虽然我不确定LINQ中是否存在钩子以允许它。假设我具有特定机器硬件(SLA)的目标性能级别。理想情况下,我会添加一个单元测试来确认通过该查询移动的典型数据将在指定的时间内(来自SLA)进行处理。问题是这将在构建服务器/开发人员机器/等上运行。这可能与SLA的机器硬件几乎没有相似之处。因此我的想法是,我将确定表达式的可接受的最大“OCount”,知道如果OCount小于X,它肯定会在目标“典型”硬件上的SLA下提供可接受的性能。如果OCount超过此阈值,则构建/单元测试将生成警告。理想情况下,我想有这样的东西(伪代码):

var results = [big linq expression run against test dataset];
Assert.IsLess(MAXALLOWABLE_OCOUNT, results.OCount)

其中results.OCount只会给出生成结果集所需的总迭代次数(n)。

我为什么喜欢这个?

嗯,即使是一个中等大小的LINQ表达式,由于增加了整体操作次数,一小部分更改/添加会对性能产生巨大影响。应用程序代码仍将通过所有单元测试,因为它仍会产生正确的结果,但在部署时工作速度很慢。

另一个原因是简单的学习。如果你做了某件事并且OCount上升或下降了一个数量级,那么你就会学到一些东西。

编辑#2 我也会提出一个可能的答案。它不是我的,它来自Cameron MacFarland我提出的另一个问题产生了这个问题。事实证明,我认为这个问题的答案可以在单元测试环境中工作,就像我在第一次编辑这个问题时所描述的那样。

它的本质是在单元测试夹具中创建测试数据集,您可以按照本答案中概述的方式将其输入LINQ表达式,然后将迭代计数相加并与最大允许迭代计数进行比较。 / p>

请参阅Cameron's answer here

3 个答案:

答案 0 :(得分:6)

你基本上需要弄清楚复杂功能。这取决于操作员,但不幸的是,它不会被很好地记录下来。

(一般原则我同意Richard的回答 - 这只是LINQ to Objects的东西。)

如果您有特定的操作员,那么您可能会对它们有所了解,但最重要的是:

  • 选择= O(n)
  • 其中= O(n)
  • 加入= O(内部+外部+匹配)(即它不比inner + outer便宜,但可能与inner * outer一样糟糕,具体取决于结果)
  • GroupJoin =与Join相同,但缓冲而不是外部
  • 流式传输
  • OrderBy = O(n log n)
  • SelectMany = O(n + results)
  • Count = O(1)或O(n)取决于它是否实现IList
  • 计数(谓词)= O(n)
  • 最大/最小= O(n)
  • 全部/任何= O(n)(可能提前退出)
  • Distinct = O(n)
  • Skip / Take = O(n)
  • SkipWhile / TakeWhile = O(n)

确切的特征取决于运营商是否缓冲或流。

答案 1 :(得分:3)

  1. 获取描述所需整体性能的SLA(或其他定义)。

  2. 衡量应用程序的性能,以及低于要求的程度(如果在要求范围内,则停止并做一些有用的事情)。

  3. 使用分析器获得详细的性能细分,确定最能够改进的系统部分(对热代码进行小幅改进可能比对很少调用的代码有很大的改进)。

  4. 进行更改,重新运行单元/功能测试(没有必要快速做错事)。

  5. 转到1.

  6. 如果在#3中你发现LINQ表达式是一个性能问题,那么就开始考虑需要回答这个问题。答案完全取决于您使用的LINQ提供程序以及在您的情况下使用它的详细信息。没有一般的答案。

答案 2 :(得分:0)

添加到正在添加到Richard

上的Jon

要考虑的另一个问题是您是否正在处理LINQ查询的所有结果。在某些情况下,尤其是UI,您最终只会处理从LINQ查询返回的结果的子集。在这些情况下,了解哪些LINQ查询支持延迟评估非常重要。这是在不处理整个集合的情况下返回结果子集的能力。

例如,对以下LINQ操作调用MoveNext()将一次处理一个结果

  • 选择
  • 其中

但是在返回单个项目之前,以下内容必须处理集合中的每个元素。

  • 排序依据
  • 除了(完全处理其他收藏)