【问题标题】:Optimize looping through large datatable优化循环大数据表
【发布时间】:2012-11-13 13:31:32
【问题描述】:

我正在使用 100 到 10000 行的数据表,通过 doyble 循环将每一行相互比较。

for (int i = 0; i < DT1.Rows.Count; i++)
{
    for (int j = 0; j < DT1.Rows.Count; j++)
    {
        //some code to compare data
    }
}

对于 100-200 行,它可以在几分钟内完成,这没关系,但是将几千行与几千行进行比较需要几个小时并且还没有完成。

我可以做些什么来加快速度?我想到的最好的办法是使用对象列表,而不是数据表。

还有其他建议吗?

线程可以用来做这个吗?

谢谢。

【问题讨论】:

  • 这些嵌套循环的目的是什么?在加速之前我们需要知道问题
  • @DenisErmolin 我通过简单的算法将每一行相互连接,并将结果写入其他表。
  • 将每一行与其他行进行比较的目的是什么?删除重复项或一些计算?
  • 是否在同一个数据库中?如果是这样,已经为这些目的构建并优化了 dbms(即使数据库不同,但在 sql server 平台上,您可以使用链接服务器功能来比较服务器上的数据)。编写一个好的存储过程,它需要几秒钟。如果您坚持自己在代码中执行此操作,则可以考虑修改该内部循环(找到正确记录时是否会中断?,数据是否有序并且可以使用二进制算法来加快速度?)
  • @jags 计算字符串相似度。查找双重消息。

标签: c# asp.net


【解决方案1】:

我最近遇到了一个我必须解决的类似情况。虽然就我而言,我正在比较一对 excel 文件。对于我的试运行,在它工作后,我在嵌套循环的一侧有 530 行,另一侧有 459000 行。这大约是 2.34 亿次迭代。我的程序能够在大约 30 秒内完成它。我在这种情况下使用了 foreach:

foreach (DataRow r1 in DT1.Rows) //Loop the First Source data
{
    foreach (DataRow r2 in DT2.Rows) //Loop the Second Source data
    {
         //Comparison code here...
    }
}

编辑:在您的循环中,作为参考点,您将在循环的每次迭代中跟踪 3 个变量,第一个和第二个是您的计数器。第三个是主要的性能影响,DT1.Rows.Count。通过使用直接行计数作为循环的一部分,必须在每次迭代时重新评估它。这给程序增加了不必要的时间。如果您绝对需要有计数器,请先分配 Row 计数:

int DT1Count = DT1.Rows.Count;
for (int i = 0; i < DT1Count; i++)
{
    for (int j = 0; j < DT1Count; j++)
    {
        //some code to compare data
    }
}

这样,行数是静态的,并且应该消除在每次迭代中评估行数所需的额外处理。

【讨论】:

    【解决方案2】:

    虽然您当然可以通过使用哈希表来优化您的搜索,但最好的优化是让数据库引擎为您搜索。 RDBMS 引擎针对此类任务进行了优化——没有客户端优化能够击败它。您最大的缺点是必须将数据从数据库中提取到您的程序中。这很慢。数据库引擎拥有所有数据 - 这是一个巨大的优势。

    例如,如果您正在寻找代表具有相同名字和姓氏的用户的行,则使用自联接的简单查询将在几秒钟内而不是几分钟内为您提供结果,因为数据永远不会离开引擎。

    select u1.userId, u2.userId
    from User u1
    join User u2 on u1.FirstName=u2.FirstName and u1.LastName=u2.LastName
    

    假设FirstNameLastName 列已编入索引,此查询将很快找到您的重复项。

    【讨论】:

    • 这是 SQL Server 中的一个表,我通过用户 ID 选择消息,然后将它们全部比较(将数据表行与自身进行比较)。
    • @xyz 看看我的例子,我从同一个表中选择用户,然后将它们全部比较。如果你有正确的索引,SQL Server 应该能够击败你写的任何东西。
    【解决方案3】:

    如果结果按某种顺序排序,您可以将结果放入数组并使用二分搜索循环

    【讨论】:

      【解决方案4】:
          for (int i = 0; i < DT1.Rows.Count; i++)
          {
            for (int j = i+1; j < DT1.Rows.Count; j++) //<-- starts from next row
            {
              //some code to compare data
            }
          }
      

      【讨论】:

        【解决方案5】:

        您还可以指望 .NET 内部结构比手动循环做得更好:

        DataTable.Select(filterExpression, sortExpression)
        

        【讨论】:

          【解决方案6】:

          这里要做的最大优化如下:
          目前,您将每个值比较两次。例如,在循环的第一次迭代中,您将第一行与自身进行比较,因为两个循环都从索引 0 开始。

          最简单的解决方法是将内部循环更改为:

          for (int j = i + 1; j < DT1.Rows.Count; j++)
          

          这将大大减少比较次数。您的算法当前需要n^2 比较。建议的修复将这个数字减少到不到一半。修复后您只需要(n^2 - n) / 2 比较。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2015-02-17
            • 1970-01-01
            • 2013-08-28
            • 1970-01-01
            • 1970-01-01
            • 2019-11-10
            • 1970-01-01
            • 2021-04-16
            相关资源
            最近更新 更多