SqlBulkCopy如何工作

时间:2012-08-29 23:13:45

标签: .net sql-server sqlbulkcopy

我熟悉C#SqlBulkCopy类,您可以在其中调用通过DataTable传递的'WriteToServer'方法。

我的问题是SQL服务器中的底层机制用于批量插入数据?

我问的原因是Bulk Insert MSDN T-SQL帮助文件中引用的批量插入需要导入数据文件。 SqlBulkCopy是否创建数据文件?

我想了解这些内容,以确定我是否可以在SQL中使用批量插入功能。

如果我编写一个SQL语句,准备将所有行插入特定表(数千行),我可以将它们批量插入到目标表中吗?这样的事情就是我现在正在做的事情,

INSERT INTO sync_filters (table_name, device_id, road_id, contract_id)
    SELECT * FROM dbo.sync_contract_filters (@device_id)

dbo.sync_contract_filters是一个生成要插入的所有行的函数。这可以批量插入吗?

3 个答案:

答案 0 :(得分:8)

SqlBulkCopy不会创建数据文件。它使用可用的通信协议(命名管道,TCP / IP等)将数据表直接从.Net DataTable对象流式传输到服务器,并使用BCP使用的相同技术将数据批量插入目标表

答案 1 :(得分:2)

SqlBulkCopy可以使用数据表,IDataReader或DataRow []作为数据源。看一下该类的WriteToServer方法。我发现它是一种非常有用的将数据导入SQL Server的机制。我之前已将此与CSVReader结合使用。上一个链接让您了解它如何与实现IDataReader的类一起工作。

您可能需要play around with the batch sizes以确保获得预期的效果。

如果您希望快速编写大量数据,那么MSDN上的

The Data Loading Performance Guide是非常有用的资源。它更侧重于BCP和BULK INSERT之类的东西,但触及SQLBulkCopy并提供了很多值得思考的东西(可能有点太多了,但至少它是一个有用的参考)。

答案 2 :(得分:0)

花了7年的时间,但我们终于有了答案...

在解释Sam Anwar的答案时,我可以确认它正在将数据转换为原始字节处理,并将其写入SQL,就像是从文件中流进来一样。 如何会欺骗SQL使其认为读取文件超出了我的范围。

我想从查询内部进行批量插入,以加快慢速聚集索引的插入。在这里找到您的帖子后,我莫名其妙地被它吸引了,所以我花了过去几个小时来研究它。

实际将数据写入服务器的执行路径似乎是:

您的代码:

  1. 您的代码调用System.Data.SqlClient.SqlBulkCopy.WriteToServer()

在System.Data.SqlClient.SqlBulkCopy内部:

  1. 调用WriteRowSourceToServerAsync()
  2. 调用WriteRowSourceToServerCommon()映射列,调用WriteToServerInternalAsync()写入数据
  3. 调用WriteToServerInternalRestContinuedAsync()
  4. 呼叫AnalyzeTargetAndCreateUpdateBulkCommand()的
  5. (这是答案。跳到步骤14进行阅读。)CopyBatchesAsync()
  6. 哪个(CopyBatchesAsync)调用SubmitBulkUpdateCommand()

-在System.Data.SqlClient.TdsParser内部:

  1. 它将调用System.Data.SqlClient.TdsParser。TdsExecuteSQLBatch()
  2. 调用WriteString()或类似方法将数据转换为字节数组
  3. 调用WriteByteArray()
  4. 调用WritePacket()
  5. 调用WriteSni()
  6. 调用SNIWritePacket()

-在System.Data.SqlClient.SNINativeMethodWrapper中:

  1. 调用System.Data.SqlClient.SNINativeMethodWrapper.SNIWritePacket()
  2. 哪个外部调用SNIWriteAsyncWrapper()或SNIWriteSyncOverAsync()

现在这是棘手的地方。我认为,这是可以的,但是我如何到达那里有点黑。我在sni.dll副本上打开了文件属性,转到“详细信息”选项卡,在“产品版本”属性中,我找到了对d0d5c7b49271cadb6d97de26d8e623e98abdc8db的“提交哈希”的引用。

因此,我googled that hash,并通过this Nuget search找到了this Nuget package,其标题包括“ System.Data.SqlClient.sni”,这意味着命名空间为 System.Data。我找到了here的SqlClient.SNI ,但是它没有正确的方法,并且实际上似乎没有与服务器通信。

所以这是我用尽专业知识的地方;在深入到我在任何地方都找不到的本机代码之前,这是我所能获得的一切。尽管我不确定上面所有其他噪音是什么...

  1. 记住步骤4(WriteToServerInternalRestContinuedAsync())也会调用AnalyzeTargetAndCreateUpdateBulkCommand()
  2. 在一个名为updateBulkCommandText的StringBuilder中连接一个SQL查询。最后一个链接中的第544行。

TLDR:最终看起来它只是执行一个 INSERT BULK 查询(不需要文件),并且实际上并没有使用 BULK INSERT (有)。请注意,这两个命令看起来非常相似。

Microsoft文档中的重要说明:

  

由外部工具用来上传二进制数据流。这个选项是   不适用于SQL Server Management Studio等工具,   SQLCMD,OSQL或数据访问应用程序编程接口,例如   作为SQL Server本机客户端。

我将其解释为“使用风险自负,不希望获得帮助”。公平地说,这几乎和绿灯一样好。