C# 优化:向数据库插入两亿行数据

5

我有下面的(简化的)代码,我想优化它的速度:

long inputLen = 50000000; // 50 million 
DataTable dataTable = new DataTable();
DataRow dataRow;
object[] objectRow;
while (inputLen--)
{
    objectRow[0] = ...
    objectRow[1] = ...
    objectRow[2] = ...

    // Generate output for this input
    output = ...

    for (int i = 0; i < outputLen; i++) // outputLen can range from 1 to 20,000
    {
         objectRow[3] = output[i];
         dataRow = dataTable.NewRow();
         dataRow.ItemArray = objectRow;
         dataTable.Rows.Add(dataRow);
    }
}

// Bulk copy
SqlBulkCopy bulkTask = new SqlBulkCopy(connection, SqlBulkCopyOptions.TableLock, null);
bulkTask.DestinationTableName = "newTable";
bulkTask.BatchSize = dataTable.Rows.Count;
bulkTask.WriteToServer(dataTable);
bulkTask.Close();

我已经在尝试使用SQLBulkCopy来加快速度,但是似乎给DataTable分配值本身就很慢。

我不知道DataTable的工作原理,所以我想知道是否先创建可重用数组,然后将其分配给DataRow,再将DataRow添加到DataTable中会产生不必要的开销?或者首先使用DataTable不是最优的选择吗?输入来自数据库。

我不太关心代码行数,只关心速度。有人可以给出一些建议吗?


要查看示例实现,请查看此处的SimpleDataReader 链接 - Marc Gravell
3个回答

13

对于这样一个大表,你应该使用

public void WriteToServer(IDataReader reader)

这可能意味着你需要自己实现一个带有你的代码的“假”IDataReader接口(如果你没有从一个现有的IDataReader获取数据),但是这样一来,你将获得端到端的“流式处理”,并且将避免200万次循环。


这是否意味着 SQLBulkCopy 可以在行被构建时高效地写入数据库?输入来自同一数据库,但对于每一行,我可能会创建 20000 个新行。 - David Tang
1
@Box9:是的,在调用SQLBulkCopy之前,数据不需要存在。我们这里有一个“遗留数据接管”应用程序,可以在大约一个小时内传输100万行(BCP输出1个表,格式化几个bcp文件,将这些文件bcp进去)。最近我们需要它运行大约4400万行,我通过实现多个IDataReader从源数据库读取数据并按照SQLBulkCopy要求的格式化行,将1小时缩短到了10分钟。 - Binary Worrier

4

建议不要在内存中保存大量数据表,而是实现一个 IDataReader,在批量复制时提供数据。这样可以减少需要一开始就将所有内容保存在内存中的需求,从而提高性能。


0

您不应该在内存中构建整个数据表。使用WrtieToServer的overload,它接受DataRow数组。只需将您的数据分成块即可。


这个方法不还是在内存中构建吗?而且,如果我没有用完内存,那么在内存中构建不是最快的吗? - David Tang
如果您一次只构建1k行而不是2亿行,那么内存管理器将更容易保持这样的数据量。此外,如果一次在内存中保存2亿条记录,几乎肯定会发生交换。 - gor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接