来自List 的SqlBulkCopy
如何从简单对象的List 中使用SqlBulkCopy进行大插入?
我是否实现了自定义IDataReader?
只需从对象列表中创建一个DataTable ,然后调用SqlBulkCopy.WriteToServer
,传递数据表。
您可能会发现以下内容有用:
- 将列添加到DataTable 。 为要写入的每个属性/字段添加一列。
- 将行添加到DataTable 。 为列表中的每个对象添加一行。
为了使用SqlBulkCopy获得最佳性能,您应该设置适当的BatchSize 。 10,000似乎运作良好 – 但您的数据配置文件。
使用SqlBulkCopyOptions.TableLock时,您可能还会观察到更好的结果。
可以在此处找到有关SqlBulkCopy性能的有趣且信息丰富的分析。
使用FastMember ,您可以在不需要通过DataTable
(在我的测试中,性能提高一倍以上)的情况下执行此操作:
using(var bcp = new SqlBulkCopy(connection)) using(var reader = ObjectReader.Create(data, "Id", "Name", "Description")) { bcp.DestinationTableName = "SomeTable"; bcp.WriteToServer(reader); }
请注意, ObjectReader
也可以使用非generics源,并且不必事先指定成员名称(尽管如果不在ObjectReader
本身中指定它们,您可能希望使用SqlBulkCopy
的ColumnMappings
方面)。
晚了,但是如果你从微软添加这个EntityDataReader
类,那么就有一个AsDataReader()
扩展方法可以做到这一点: https : //github.com/matthewschrager/Repository/blob/master/Repository.EntityFramework/EntityDataReader.cs
(示例[List].AsDataReader()
实现:)
var connStr = ""; using (var connection = new SqlConnection(connStr)) { var startTime = DateTime.Now; connection.Open(); var transaction = connection.BeginTransaction(); try { //var connStr = connection.ConnectionString; using (var sbCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.Default, transaction)) { sbCopy.BulkCopyTimeout = 0; sbCopy.BatchSize = 10000; sbCopy.DestinationTableName = "Foobars"; var reader = Foobars.AsDataReader(); sbCopy.WriteToServer(reader); } transaction.Commit(); } catch (Exception ex) { Console.WriteLine(ex.Message); transaction.Rollback(); } finally { transaction.Dispose(); connection.Close(); var endTime = DateTime.Now; Console.WriteLine("Upload time elapsed: {0} seconds", (endTime - startTime).TotalSeconds); } }
根据您尝试通过首先调用SqlBulkCopy
来完成的任务,使用表值参数(TVP)可能更有意义。 使用TVP会使发送任何自定义类型的集合变得微不足道。 数据可以流式传输,因此您可以避免使用DataTable
(很像@Marc Gravell的答案),您也可以避免使用SqlBulkCopy
。 当您调用存储过程将TVP数据传入其中时,TVP允许完全灵活地处理数据到达SQL Server,并且它显示为可以执行任何操作的表变量,而不仅仅是INSERT
(这是使用SqlBulkCopy
情况)。 您还可以通过SqlDataReader
获取数据,例如新创建的IDENTITY
值等数据。 我在这个答案中添加了一个示例和一些附加说明: 如何在最短的时间内插入1000万条记录? 。 几年前我写了一篇关于SQL Server Central的文章(需要免费注册), 从一个应用程序将数据流式传输到SQL Server 2008 ,这也是在链接的答案中提到的,提供了一个传递自定义通用列表的工作示例类型,从300万行文本文件中流入。
- 当DbDataAdapter.Update调用时,为什么我使用ODP.NET OracleDataAdapter获取OracleTruncateException而不使用System.Data.OracleClient的适配器?
- 如何在给定DbCommand或DbConnection的情况下创建DbDataAdapter?
- 在一次往返中执行多个SQL命令
- 如果使用using子句,是否需要关闭DbConnection?
- 数据库连接池如何影响性能?
- 全外连接,在2个数据表上,带有列列表
- ADO.NET中断开连接方法的确切含义是什么
- 如何在我的应用程序中使用SELECT语句,该语句必须返回多个记录以显示某个字段的多个值(m:m关系)
- 在ListView控件中隐藏ID列