【问题标题】:Is there a faster way to use SqlBulkCopy than using a DataTable?有没有比使用 DataTable 更快的方法来使用 SqlBulkCopy?
【发布时间】:2017-11-09 16:51:29
【问题描述】:

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

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

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

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

但是SqlBulkCopy 需要(我相信)DataTable - 并且将我的记录加载到 DataTable 很慢 - 大约每分钟使用 7500 条记录

dataTable.Rows.Add(myRecord.Name, myRecord.Age, ....)

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

【问题讨论】:

  • 你见过stackoverflow.com/questions/13722014/…吗(那里声称每秒100万行)?您的 DataTable 是否有任何索引、键、表达式列、约束、与其他表的关系等,或者它是否尽可能简单?
  • 我的数据表非常简单,一些字符串、整数和日期时间字段,没有多余的
  • 删除,因为在对这些答案进行调查后,发现问题是一个简单的查找,它被卡在了基准测试代码中。
  • @MethodMan 至于“简单真棒的过程”,我现在正在从 8 个不同的系统加载数据——数据库、FTP、S3 文件、IATA HOT 文件(特殊解析)、屏幕抓取、Web 服务(即 XML)、REST 服务,在 SSIS 数据流中匹配它们以查找差异。我什至使用 TPL Dataflow 来解析文本文件、转换它们并将它们插入数据库,同时将它们写入文本文件以进行导入。 TPL Dataflow 也允许我并行处理多个请求,例如一次 10 个 REST 查询

标签: c# sql-server sqlbulkcopy


【解决方案1】:

延迟是因为您必须在将所有内容发送到服务器之前将其缓冲到 DataTable 中。为了获得更好的性能,您应该立即将记录发送到 SqlBulkCopy,并让该类使用自己的缓冲和批处理。

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

在其他情况下,假设您的对象有一个 IEnumerable,您可以使用 FastMember 包中的 Marc Gravel 的 ObjectReader 在 IEnumerable 之上创建一个 IDataReader。此数据读取器不会一次加载所有内容,因此在 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); 
}

【讨论】:

    【解决方案2】:

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

           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();
            }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-10-10
      • 2015-01-14
      • 1970-01-01
      • 2018-01-12
      • 1970-01-01
      • 1970-01-01
      • 2011-03-24
      • 2013-03-10
      相关资源
      最近更新 更多