【问题标题】:C# LINQ and calculations involving large datasetsC# LINQ 和涉及大型数据集的计算
【发布时间】:2011-08-24 11:22:27
【问题描述】:

这更像是一个技术性的“操作方法”或“最佳方法”问题。

我们当前的需求是从数据库中检索记录,将它们放入“内存中”列表,然后对数据执行一系列计算,即最大值、平均值和一些更具体的自定义统计数据。

将数据放入“内存中”列表不是问题,因为我们使用 NHibernate 作为我们的 ORM,它在从数据库中检索数据方面做得很好。我正在寻求的建议是我们应该如何最好地对结果数据列表进行计算。

理想情况下,我想为每个统计数据创建一个方法,MaximumValue()、AverageValueUnder100()、MoreComplicatedStatistic() 等。当然,将所需的变量传递给每个方法并让它返回结果。这种方法还可以让单元测试变得轻而易举,并为我们提供出色的覆盖率。

如果我们为每个计算执行一个 LINQ 查询,或者应该在尽可能少的 LINQ 查询中合并对每个统计方法的尽可能多的调用,是否会影响性能。例如,将数据列表传递给一个名为 AverageValueBelow100 的方法,然后将整个数据列表传递给另一个方法 AverageValueBelow50,这样可以有效地使用一个 LINQ 查询来执行它们是没有多大意义的。

我们如何在不牺牲性能的情况下实现高粒度和分离度?

任何建议......问题是否足够清楚?

【问题讨论】:

  • 最好的方法是对数据库执行查询,您可以利用索引来提高性能
  • 真的吗?因此,与其处理“内存中”,不如查询数据库。一些计算非常复杂,所以我不完全确定这是最好的方法。
  • 大多数情况下数据库更快
  • @Rowen 数据库也在“内存中”执行此操作,但它具有额外的信息,例如内置索引,可以在执行计算时以低得多的时间复杂度进行一些查找。
  • Linq 不能比每个定义的 DB 快。怎么会这样?它只是在上面执行 SQL。不能比在数据库上执行相同的 SQL 更快。您可能想要构建 IQueryables,而不是拉入列表,您可以在其上“堆叠”不同的 Linq 表达式并延迟执行,这样您就只执行您想要的并且与您需要的数据相关。

标签: c# linq performance list


【解决方案1】:

根据计算的复杂程度,可能最好在数据库中进行。如果您需要将其作为对象引入并产生开销非常复杂,您可能希望避免对结果集进行多次迭代。您可能需要考虑使用聚合。如果有讨论,请参阅http://geekswithblogs.net/malisancube/archive/2009/12/09/demystifying-linq-aggregates.aspx。您可以单独对每个聚合进行单元测试,然后(可能)在一次迭代中投影多个聚合。

【讨论】:

    【解决方案2】:

    我不同意最好“在数据库中完成所有操作”。

    编写良好的 Linq 查询将导致对数据库执行良好的 SQL 查询,这在性能方面应该足够好(如果您不打算做 dwh 的事情)。这是假设您使用的是 NHibernate 的 Linq Provider 而不是 Linq to Objects。

    它看起来不错,您可以轻松更改它并将您的业务逻辑保存在一个地方。

    如果这对您的需求来说太慢了,您可以检查创建的 SQL 代码并调整您的 linq 查询,尝试预编译它们,最后您仍然可以回到编写心爱的存储过程 - 并开始将您的业务逻辑传播到各处。

    性能会受到影响吗?是的,您可能会损失几毫秒,但这值得您为分离逻辑而付出的代价吗?

    【讨论】:

    • 我不建议在数据库中完成所有操作。我只是建议不要在内存中获取所有数据,然后执行有效的 Linq 对象查询。
    【解决方案3】:

    要回答“我想为每个统计数据创建一个方法”的问题,我建议您构建一种统计学家类。这里有一些伪代码来表达这个想法:

    class Statistician
    {
        public bool MustCalculateFIRSTSTATISTIC { get; set; }   // Please rename me!
        public bool MustCalculateSECONDSTATISTIC { get; set; }  // Please rename me!
    
        public void ProcessObject(object Object) // Replace object and Rename
        {
            if (MustCalculateFIRSTSTATISTIC)
                CalculateFIRSTSTATISTIC(Object);
    
            if (MustCalculateFIRSTSTATISTIC)
                CalculateSECONDSTATISTIC(Object);
        }
    
        public object GetFIRSTSTATISTIC() // Replace object, Rename
        { /* ... */ }
        public object GetSECONDSTATISTIC() // Replace object, Rename
        { /* ... */ }
    
        private void CalculateFIRSTSTATISTIC(object Object) // Replace object
        { /* ... */ }
        private void CalculateSECONDSTATISTIC(object Object) // Replace object
        { /* ... */ }
    }
    

    我是否必须这样做,我可能会尝试使其通用并使用委托集合而不是方法,但由于我不知道您的上下文,所以我会留给它。另请注意,我只使用了对象类的对象成员,但这只是因为我不建议您使用 DataRows、Entities 或其他什么;我会把它留给其他比我更了解这个主题的人!

    【讨论】:

      猜你喜欢
      • 2017-04-07
      • 2011-03-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多