循环遍历很多行

Posted

技术标签:

【中文标题】循环遍历很多行【英文标题】:Looping through a lot of rows 【发布时间】:2012-03-11 01:41:00 【问题描述】:

我在循环访问数据库中大约 100 万条潜在行时遇到了时间问题。我基本上将行拉入 DataTable 并循环遍历它们,但它变得越来越慢。那里有什么替代方案?我可以将这些行分成块,比如每块 20,000 个。我可以在 C# 中使用并行处理吗?基本上,代码会遍历与某个查询匹配的每条潜在记录,并尝试确定它是否是合法条目。这就是为什么需要单独访问每条记录的原因。一个对象的记录可能达到 1000 万行。方法看起来像是多台计算机中的并行处理或多核单机中的 PP,或者某种数据结构/方法的变化?

有什么意见、想法和猜测有助于快速合理地完成这个过程吗?

【问题讨论】:

【参考方案1】:

首先:请勿将DataTable 用于此类操作

很慢 它消耗了太多内存 您需要等待很长时间才能真正开始处理数据 在这段时间里,额外的内核什么都不做,因为将数据读入DataTable 没有被parralized。 此外,在读取数据时,CPU 通常几乎没有得到充分利用,因为网络或其他 I/O 延迟通常是主要因素。

再说一遍:不要将DataTable 用于此类操作。

改为使用DataReader。这使您可以立即开始使用/处理数据,而不是等待它被加载。最简单的版本是(MS SQL Server 的示例):

var command = new SqlCommand()

  CommandText = "SELECT * FROM Table";
  Connection = new SqlConnection("InsertConnectionString");
;

using(var reader = command.ExecuteReader())

  while(reader.Read())
  
    var values = new object[reader.FieldCount];
    reader.GetValues(values);

    // process values of row
  

读取器将在执行处理代码时被阻止,这意味着不再从数据库中读取行。 如果处理代码很繁重,使用Task 库创建执行检查的任务可能是值得的,这将使您能够使用多个内核。但是,创建Task 会产生开销,如果一个Task 不包含足够的“工作”,您可以将几行一起批处理:

public void ReadData()

  var taskList = new List<Task<SomeResultType>>();

  var command = new SqlCommand()
  
    CommandText = "SELECT * FROM Table";
    Connection = new SqlConnection("InsertConnectionString");
  ;
  using(var reader = command.ExecuteReader())
  
    var valueList = new List<object[]>(100);
    while(reader.Read())
    
      var values = new object[reader.FieldCount];
      reader.GetValues(values);

      valueList.Add(values);

      if(valueList.Count == 100)
      
        var localValueList = valueList.ToList();
        valueList.Clear();

        taskList.Add(Task<SomeResultType>.Factory.StartNew(() => Process(localValueList));
      
    
    if(valueList.Count > 0)
      taskList.Add(Task<SomeResultType>.Factory.StartNew(() => Process(valueList));
  

  // this line completes when all tasks are done
  Task.WaitAll(taskList.ToArray());


public SomeResultType Process(List<object[]> valueList)

  foreach(var vals in valueList)
  
    // put your processing code here, be sure to synchronize your actions properly
    

批量大小(当前为 100)取决于正在执行的实际处理,可能需要调整。 同步有其自身的挑战,您需要非常小心共享资源

【讨论】:

很好的解释但我有一些问题:1-哪个会更好,您建议的解决方案或执行多个任务,每个任务都使用 SQLReader 从数据库中读取一系列行(例如基于分页)特别是在结果处理不是很繁重的情况下。 2-Task BackgroundWork 之间的性能有显着差异吗?【参考方案2】:

我建议使用双核机器进行并行循环,并尝试使用通用列表对每个循环使用,我认为这可能会使您的过程更快。

【讨论】:

以上是关于循环遍历很多行的主要内容,如果未能解决你的问题,请参考以下文章

循环遍历很多行

Excel VBA ADO查询循环太多行

Oracle - 匿名过程循环遍历多个表(动态) - 查询返回多行

将多行的 heightForRowAt indexPath 设置为 0

如果不逐行遍历数据框,这需要很长时间,我如何检查多行是不是都满足条件?

高效更新 SQL,一条 SQL 语句更新多行,避免循环