有没有比使用 DataTable 更快的方法来使用 SqlBulkCopy?

Is there a faster way to use SqlBulkCopy than using a DataTable?

我将大量记录加载到我的应用程序中(超过 100 万条)并对它们进行大量处理。处理要求它们都在内存中。

之后,我想将所有(现在已修改的)记录转储到一个空的 table。

加载记录只需几秒钟,我最终得到了一大堆 MyRecord 项。

使用 SqlBulkCopy 保存也只需几秒钟。

但是 SqlBulkCopy 需要(我相信)DataTable - 将我的记录加载到 DataTable 很慢 - 使用

每分钟大约 7500 条记录
dataTable.Rows.Add(myRecord.Name, myRecord.Age, ....)

有没有更快的方法来执行这个中间步骤?

我不知道是什么问题。下面的程序运行不到一秒钟。我怀疑速度慢是由于读取数据而不是写入数据表造成的。

       static void Main(string[] args)
        {
            DataTable dt = new DataTable();
            dt.Columns.Add("Col A", typeof(int));
            dt.Columns.Add("Col B", typeof(string));
            dt.Columns.Add("Col C", typeof(int));
            dt.Columns.Add("Col D", typeof(string));
            dt.Columns.Add("Col E", typeof(int));
            dt.Columns.Add("Col F", typeof(string));
            dt.Columns.Add("Col G", typeof(int));
            dt.Columns.Add("Col H", typeof(string));
            dt.Columns.Add("Col I", typeof(int));
            dt.Columns.Add("Col J", typeof(string));

            DateTime begin = DateTime.Now;

            for (int i = 0; i < 7500; i++)
            {
                dt.Rows.Add(new object[] {
                    i + 10000, "b", i + 20000, "d", i + 30000, "f", i + 40000, "h", i + 50000, "i"
                });
            }

            DateTime end = DateTime.Now;

            Console.WriteLine((end - begin).ToString());

            Console.ReadLine();
        }

造成延迟的原因是您必须先将所有内容缓冲到 DataTable 中,然后再将其发送到服务器。为了获得更好的性能,您应该立即将记录发送到 SqlBulkCopy,并让 class 使用它自己的缓冲和批处理。

SqlBulkCopy 可以与 IDataReader 一起使用。所有 ADO.NET 数据 reader 实现此接口,因此您可以将您从任何数据 reader 读取的数据推送到 SqlBulkCopy。

在其他情况下,假设您有一个 IEnumerable 对象,您可以使用 FastMember 包中的 Marc Gravel 的 ObjectReader 在 IEnumerable 之上创建一个 IDataReader。此数据 reader 不会 一次加载所有内容,因此在 SqlBulkCopy 请求之前不会缓存任何数据:

复制 Marc Gravel 的示例:

IEnumerable<SomeType> data = ... 

using(var bcp = new SqlBulkCopy(connection)) 
using(var reader = ObjectReader.Create(data, "Id", "Name", "Description")) 
{ 
  bcp.DestinationTableName = "SomeTable"; 
  bcp.WriteToServer(reader); 
}