Sql-Server

將數據集合插入 SQL Server 數據庫的最佳實踐是什麼

  • December 27, 2017

我正在使用 C#,實體框架。用於開發的 SQL Server。我有一個有兩個參數(int ID, List<String> _listobj)的方法。對於每個 ID,都有一個 obj 列表。所有這些 ID 和列表都將插入到數據庫中的不同表中。所以問題是:最好的做法是什麼?我有幾個選擇:

  1. 在 C# 中,將其拆分list<obj>為單個值,然後創建一個帶有兩個參數 ( ID, str) 的儲存過程,然後 C# 將根據列表的大小多次呼叫儲存過程
  2. IDandlist<obj>作為兩個參數傳遞給儲存過程,讓儲存過程拆分list<obj>. 這樣C#只會呼叫一次儲存過程

第二種策略可行嗎?如果是,在性能方面哪個更好?

您不想要這兩個選項中的任何一個,儘管 #2 非常接近。選項 #1 由於是逐行的,並且每個呼叫都是其自己的單獨事務,因此速度很慢。即使您將所有儲存過程呼叫包裝到單個顯式事務中,它仍然會比基於集合的方法慢。

選項 #2 的缺陷主要在於在兩層中完成的額外工作:將集合加入應用層中的單個字元串,並將字元串拆分回數據層中的元素。然而,這個想法的一般結構——只傳遞兩個參數:ID 和字元串的集合——是要走的路。您只需要使用表值參數 (TVP),以便您可以按原樣遍歷集合,並將其作為 SQL Server 中的預填充表變數接收。

為此,您可以創建一個使用者定義的表類型(此處可以是單列NVARCHAR)並將其用作集合的參數(因此是“表”-值“參數”)。

這個難題的另一部分是,在應用程式碼方面,創建一個接受int ID, List<String> _listobj和返回的方法IEnumerable<SqlDataRecord>,然後將該方法用作SqlParameter映射到 TVP 的“值”。意思是,類似於:

private static IEnumerable<SqlDataRecord> SendRows(List<String> RowData)
{
  SqlMetaData[] _TvpSchema = new SqlMetaData[] {
     new SqlMetaData("SomeSomething", SqlDbType.NVarChar, 4000)
  };
  SqlDataRecord _DataRecord = new SqlDataRecord(_TvpSchema);

  foreach (string _CurrentRow in RowData)
  {
     _DataRecord.SetString(0, _CurrentRow);

     yield return _DataRecord;
  }
}

然後,您只需SendRows(_listobj)作為 TVP 參數的值傳入。當您執行時SqlCommand,它將呼叫該方法並將該集合流式傳輸到 SQL Server。

上面顯示的技術不需要額外的記憶體或處理,它只是將集合作為集合發送。不需要DataTables 或String.Joining 或拆分 :-)。

要查看完整的範常式式碼設置,請參閱我對以下堆棧溢出問題的回答:將字典傳遞給儲存過程 T-SQL

第二種方法是可行的。您可以將逗號分隔的字元串傳遞給 SP,並在 SP 中使用自定義 sql 表值函式,如下所示:

CREATE FUNCTION [dbo].[fn_Split](@text VARCHAR(MAX), @delimiter VARCHAR(5) = ',')

RETURNS @Strings TABLE
(    
   position int IDENTITY PRIMARY KEY,
   value VARCHAR(8000)  
)

AS
BEGIN
   DECLARE @index int 
   SET @index = -1 

   WHILE (LEN(@text) > 0) 
       BEGIN  
           SET @index = CHARINDEX(@delimiter , @text)  

           IF (@index = 0) AND (LEN(@text) > 0)  
               BEGIN   
                   INSERT INTO @Strings VALUES (@text)
                   BREAK  
               END  

           IF (@index > 1)
               BEGIN
                   INSERT INTO @Strings VALUES (LEFT(@text, @index - 1))
               END

           SET @text = RIGHT(@text, (LEN(@text) - (@index+LEN(@delimiter)-1))) 
       END
   RETURN
END

或者您可以定義自定義表類型,如 foll 並從 C# 呼叫您的 SP,使用 SqlDbType.Structured 將表變數作為第二個參數傳遞

CREATE TYPE [dbo].[MyCustomType] AS TABLE(
Id int not null
)

引用自:https://dba.stackexchange.com/questions/152347