SqlBulkCopy 是如何工作的
我熟悉 C# SqlBulkCopy 類,您可以在其中呼叫通過 DataTable 傳遞的“WriteToServer”方法。
我的問題是 SQL Server 中的什麼底層機制用於批量插入該數據?
我問的原因是批量插入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 是一個生成所有要插入的行的函式。這個可以批量插入嗎?
SqlBulkCopy 不創建數據文件。它使用可用的通信協議(命名管道、TCP/IP 等)將數據表直接從 .Net DataTable 對象流式傳輸到伺服器,並使用 BCP 使用的相同技術將數據批量插入目標表.
花了7年,但我們終於有了答案……
根據 Sam Anwar 的回答,我可以確認它正在將數據轉換為原始字節流並將其寫入 SQL,就好像它是從文件中流入一樣。它如何欺騙 SQL 使其認為它正在讀取文件超出了我的理解。
我想從查詢內部進行批量插入,以加快慢速聚集索引插入。在這裡找到你的文章後,不知何故,我對它產生了令人不安的興趣,所以我花了幾個小時研究它。
實際向伺服器寫入數據的執行路徑似乎是:
您的程式碼:
- 您的程式碼呼叫 System.Data.SqlClient.SqlBulkCopy.WriteToServer()
System.Data.SqlClient.SqlBulkCopy 內部:
- 它呼叫WriteRowSourceToServerAsync ()
- 它呼叫WriteRowSourceToServerCommon () 來映射列並呼叫WriteToServerInternalAsync () 來寫入數據
- 它呼叫WriteToServerInternalRestContinuedAsync ()
- 它呼叫了 AnalyzeTargetAndCreateUpdateBulkCommand () *(這就是答案。跳到第 14 步來閱讀它。)*和CopyBatchesAsync ()
- 其中 (CopyBatchesAsync) 呼叫SubmitBulkUpdateCommand ()
– 在 System.Data.SqlClient.TdsParser 內部:
- 它呼叫 System.Data.SqlClient.TdsParser。TdsExecuteSQLBatch ()
- 它呼叫WriteString () 或類似方法將數據轉換為字節數組
- 它呼叫WriteByteArray ()
- 它呼叫WritePacket ()
- 它呼叫WriteSni ()
- 呼叫SNIWritePacket ()
– 在 System.Data.SqlClient.SNINativeMethodWrapper 內部:
- 它呼叫System.Data.SqlClient.SNINativeMethodWrapper.SNIWritePacket ()
- 哪個外部呼叫SNIWriteAsyncWrapper () 或SNIWriteSyncOverAsync ()
現在這是棘手的地方。我認為這如下,但我是如何到達那裡的有點hacky。我打開了我的 sni.dll 副本上的文件屬性,轉到詳細資訊選項卡,在 Product Version 屬性中,我找到了對 d0d5c7b49271cadb6d97de26d8e623e98abdc8db 的“送出雜湊”的引用。
所以我用Google搜尋了那個雜湊,通過這個 Nuget 搜尋我找到了這個 Nuget 包,它的標題包括“System.Data.SqlClient.sni”,這意味著我在這裡找到的命名空間System.Data.SqlClient.SNI ,但這並沒有’沒有正確的方法,實際上似乎沒有與伺服器通信。
所以這就是我用盡專業知識的地方;在它進入我在任何地方都找不到的本機程式碼之前,這是我所能達到的深度。雖然我不確定上面的所有其他噪音是什麼……
- 記住第 4 步(WriteToServerInternalRestContinuedAsync ())也呼叫了 AnalyzeTargetAndCreateUpdateBulkCommand ()
- 它在名為 updateBulkCommandText 的 StringBuilder 中連接一個 SQL 查詢。最後一個連結中的第 544 行。
TLDR:最終,它似乎只是執行了一個*INSERT BULK查詢(不需要文件),實際上並沒有使用BULK INSERT*(確實如此)。請注意,這兩個命令看起來非常相似。
Microsoft 文件中的重要說明:
由外部工具用於上傳二進制數據流。此選項不適用於 SQL Server Management Studio、SQLCMD、OSQL 等工具或 SQL Server Native Client 等數據訪問應用程序程式介面。
我將其解釋為“使用風險自負,不要指望幫助”。公平地說,這幾乎和綠燈一樣好。