C# 使用SqlBulkCopy是否有比使用DataTable更快的方法?
我将大量记录加载到我的应用程序中(100万条以上),并对它们进行大量处理。处理要求它们都在内存中 之后,我想将所有(现在已修改的)记录转储到一个空表中 加载记录只需几秒钟,我就得到了大量的C# 使用SqlBulkCopy是否有比使用DataTable更快的方法?,c#,sql-server,sqlbulkcopy,C#,Sql Server,Sqlbulkcopy,我将大量记录加载到我的应用程序中(100万条以上),并对它们进行大量处理。处理要求它们都在内存中 之后,我想将所有(现在已修改的)记录转储到一个空表中 加载记录只需几秒钟,我就得到了大量的MyRecord项 使用SqlBulkCopy保存也只需几秒钟 然而,SqlBulkCopy需要(我相信)一个DataTable——并且将我的记录加载到DataTable中的速度很慢——使用 dataTable.Rows.Add(myRecord.Name, myRecord.Age, ....) 有没有更快
MyRecord
项
使用SqlBulkCopy
保存也只需几秒钟
然而,SqlBulkCopy
需要(我相信)一个DataTable
——并且将我的记录加载到DataTable
中的速度很慢——使用
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();
}
static void Main(字符串[]args)
{
DataTable dt=新的DataTable();
添加(“A列”,类型(int));
添加(“B列”,类型(字符串));
添加(“C列”,类型(int));
添加(“D列”,类型(字符串));
添加(“列E”,类型(int));
添加(“F列”,类型(字符串));
添加(“G列”,类型(int));
添加(“H列”,类型(字符串));
添加(“第I列”,类型(int));
添加(“第J列”,类型(字符串));
DateTime begin=DateTime.Now;
对于(int i=0;i<7500;i++)
{
dt.Rows.Add(新对象[]){
i+10000,“b”,i+20000,“d”,i+30000,“f”,i+40000,“h”,i+50000,“i”
});
}
DateTime end=DateTime.Now;
WriteLine((end-begin.ToString());
Console.ReadLine();
}
造成延迟的原因是,在将数据发送到服务器之前,必须将所有内容缓冲到数据表中。为了获得更好的性能,应该立即将记录发送到SqlBulkCopy,并让类使用自己的缓冲和批处理
SqlBulkCopy可以与IDataReader一起使用。所有ADO.NET数据读取器都实现此接口,因此您可以将从任何数据读取器读取的数据推送到SqlBulkCopy
在其他情况下,假设您有一个IEnumerable对象,您可以从包中使用Marc Grasser的ObjectReader在IEnumerable上创建IDataReader。此数据读取器不会一次加载所有数据,因此在SqlBulkCopy请求之前不会缓存任何数据:
复制Marc Grasser的示例:
IEnumerable<SomeType> data = ...
using(var bcp = new SqlBulkCopy(connection))
using(var reader = ObjectReader.Create(data, "Id", "Name", "Description"))
{
bcp.DestinationTableName = "SomeTable";
bcp.WriteToServer(reader);
}
IEnumerable数据=。。。
使用(var bcp=new SqlBulkCopy(连接))
使用(var reader=ObjectReader.Create(数据,“Id”、“名称”、“描述”))
{
bcp.DestinationTableName=“SomeTable”;
bcp.WriteToServer(读卡器);
}
你见过(那里的家伙声称每秒100万行)吗?您的DataTable是否有任何索引、键、表达式列、约束、与其他表的关系等,或者它尽可能简单?我的DataTable非常简单,有些字符串,int和datetime字段没有任何额外内容?删除,因为在使用这些答案进行调查后,发现问题是一个简单的查找在基准代码中遇到了问题。@MethodMan至于“简单的可怕过程”,我现在正在加载8个不同系统的数据-数据库、FTP、S3文件、IATA热文件(特殊解析),屏幕抓取、web服务(ie XML)、REST服务,在SSIS数据流中匹配它们以发现差异。我甚至使用TPL数据流来解析文本文件,转换它们并将它们插入数据库,同时将它们写入文本文件以进行导入。TPL数据流也允许我并行处理多个请求,例如一次处理10个REST查询