將數據集合插入 SQL Server 數據庫的最佳實踐是什麼
我正在使用 C#,實體框架。用於開發的 SQL Server。我有一個有兩個參數(
int ID, List<String> _listobj
)的方法。對於每個 ID,都有一個 obj 列表。所有這些 ID 和列表都將插入到數據庫中的不同表中。所以問題是:最好的做法是什麼?我有幾個選擇:
- 在 C# 中,將其拆分
list<obj>
為單個值,然後創建一個帶有兩個參數 (ID, str
) 的儲存過程,然後 C# 將根據列表的大小多次呼叫儲存過程- 將
ID
andlist<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。上面顯示的技術不需要額外的記憶體或處理,它只是將集合作為集合發送。不需要
DataTable
s 或String.Join
ing 或拆分 :-)。要查看完整的範常式式碼設置,請參閱我對以下堆棧溢出問題的回答:將字典傳遞給儲存過程 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 )