SqlBulkCopy如何工作

pet*_*ter 11 .net sql-server sqlbulkcopy

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

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

我问的原因是批量插入 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)
Run Code Online (Sandbox Code Playgroud)

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

小智 10

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


tsi*_*ilb 6

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

在阐述 Sam Anwar 的回答时,我可以确认它正在将数据转换为原始字节流并将其写入 SQL,就好像它是从文件中流入一样。它如何诱使 SQL 认为它正在读取文件超出了我的理解。

我想从查询内部进行批量插入,以加速缓慢的聚集索引插入。在这里找到您的帖子后,不知何故我变得令人不安,因此我花了几个小时研究它。

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

您的代码:

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

System.Data.SqlClient.SqlBulkCopy 里面:

  1. 其中调用WriteRowSourceToServerAsync ()
  2. 调用WriteRowSourceToServerCommon ()映射列,调用WriteToServerInternalAsync ()写入数据
  3. 其中调用WriteToServerInternalRestContinuedAsync ()
  4. 它调用AnalyzeTargetAndCreateUpdateBulkCommand () (这是答案。跳到第 14 步阅读它。)CopyBatchesAsync ()
  5. 其中 (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. 其中extern调用SNIWriteAsyncWrapper () 或SNIWriteSyncOverAsync ()

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

所以我用谷歌搜索了那个哈希,通过这个 Nuget 搜索我找到了这个 Nuget 包,它的标题包括“System.Data.SqlClient.sni”,这意味着命名空间System.Data.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 Native Client 等数据访问应用程序编程接口。

我将其解释为“使用风险自负,不要指望帮助”。平心而论,这几乎和绿灯一样好。