近來有一個項目Feature須要有批量寫入數據的場景,正巧整理資料發現本身之前也相似實現的項目,在重構的同時把相關資料作了一個簡單的梳理,方便你們參考。sql
在SQL Server 2008未提供表值參數以前,須要將多行數據傳遞到存儲過程或參數化sql命令咱們通常會採用如下幾個方法:服務器
方案一app
做爲早期學習時出鏡率最高的的實現方法我在這裏就不特別說明了,在這裏直接上碼及測試數據:ide
public static void NormalInsertDate(DataTable dt) { using (var sqlConn = new SqlConnection(_testDataConnectionString)) { var sql = "INSERT INTO Student(Name,Age) VALUES(@Name,@Age)"; using (var cmd = new SqlCommand(sql, sqlConn)) { sqlConn.Open(); cmd.Parameters.Add("@Name", SqlDbType.NVarChar, 50); cmd.Parameters.Add("@Age", SqlDbType.Int); for (int i = 0; i < dt.Rows.Count; i++) { cmd.Parameters["@Name"].Value = dt.Rows[i]["Name"]; cmd.Parameters["@Age"].Value = dt.Rows[i]["Age"]; cmd.ExecuteNonQuery(); } } } }
圖一爲每次10k條,寫10次共計100k條數據總計15329ms工具
圖二爲每次100k條,寫10次共計1000k條數據總計184395ms學習
方案二測試
做爲早期批量寫入的救星,批量寫入的出鏡指數4顆星。如下爲測試數據:ui
public static void BulkInsertData(DataTable dt) { using (var sqlConn = new SqlConnection(_testDataConnectionString)) { using (var bulkCopy = new SqlBulkCopy(sqlConn) { DestinationTableName = "Student", BatchSize = dt.Rows.Count }) { sqlConn.Open(); bulkCopy.WriteToServer(dt); } } }
圖一爲每次10k條,寫10次共計100k條數據總計1848msspa
圖二爲每次100k條,寫10次共計1000k條數據總計21584ms設計
方案三表值參數方式寫入
表值參數提供一種將客戶端應用程序中的多行數據封送到 SQL Server 的簡單方式,而不須要屢次往返或特殊服務器端邏輯來處理數據。您可使用表值參數來包裝客戶端應用程序中的數據行,並使用單個參數化命令將數據發送到服務器。傳入的數據行存儲在一個表變量中,而後您能夠經過使用 Transact-SQL 對該表變量進行操做。
可使用標準的 Transact-SQL SELECT 語句來訪問表值參數中的列值。表值參數爲強類型,其結構會自動進行驗證。表值參數的大小僅受服務器內存的限制。
注意:表值參數只能是輸入參數,不能做爲輸出參數。
如下爲相關實現:
1.建立表值參數類型(UDT)
USE Test --CREATE TABLE CREATE TABLE Student ( Id INT IDENTITY(1,1) PRIMARY KEY, Name NVARCHAR(50), Age INT ) --create table parameter type CREATE TYPE StudentUDT AS TABLE ( Name NVARCHAR(50), Age INT )
public static void TableParameterInsertData(DataTable dt) { using (var sqlConn = new SqlConnection(_testDataConnectionString)) { var sql = "INSERT INTO Student(Name,Age) SELECT Name, Age FROM @StudentTVPS";//在這裏直接訪問表值參數 using (var cmd = new SqlCommand(sql, sqlConn)) { var catParam = cmd.Parameters.AddWithValue("@StudentTVPS", dt); catParam.SqlDbType = SqlDbType.Structured; catParam.TypeName = "StudentUDT";//咱們自定義的表值參數類型名稱 sqlConn.Open(); cmd.ExecuteNonQuery(); } } }
圖一爲每次10k條,寫10次共計100k條數據總計390ms
圖二爲每次100k條,寫10次共計1000k條數據總計4451ms
最後咱們再橫向比較一下:
就我本機測試的狀況來看,normal=9*bulk=42*tvps
另外我就一次性大量數據寫入對bulk和tvps單獨進行了測試,一次性寫入100K條數據兩種方案基本持平490ms
但在一次性寫入1000K條數據時差距又再次被拉開,bulk=1.5tvps
就測試數據代表bulk在一次性大量寫入依然有不小的優點,畢竟ms就是專門讓他來作這個事情的。
然而也能夠經過tvps進行分範圍寫入的方式,總消耗時間有小幅度改善。
全部呢,有大量數據一次性寫入場景直接使用bulk copy方式吧。他當仁不讓能夠高效完成使命。
若是就一些普通業務批量場景無需考慮直接上TVPS方式。他的效率相對於較以前xml參數,複雜參數實現批量寫入已是數量級的提高。
你絕對值得擁有。
因爲客戶端硬件環境緣由,測試環境應該不能很是精確。因此以上數據僅供參考。
歡迎你們一塊兒分享交流。
附件本機測試硬件環境:i7 4770+128 ssd+8G內存;