一. 簡介html
1. 背景:數據庫
雖然前面EF的擴展插件Z.EntityFramework.Extensions,性能很快,並且也很方便,可是該插件要收費,使用免費版本的話,須要按期更新,若是不更新,將失效,很是麻煩,這個時候SqlBulkCopy類既免費又高效,顯得很是合適了。app
2. 使用步驟:ide
①. 引入命名空間:using System.Data.SqlClient;post
②. 使用DataTable構造與目標數據庫表結構相同的字段,並給其賦值。性能
③. 使用SqlBulkCopy類,將內存表中的數據一次性插入到目標表中。(看下面的封裝可知,能夠自行設置插入塊的大小)測試
補充:調用下面的封裝這種形式必須內存表中的字段名和數據庫表中的字段名一一對應。大數據
二. 使用方式及其性能測試ui
1. 涉及到的數據庫結構:url
2. 數據庫鏈接字符串
<add name="CodeFirstModel2" connectionString="data source=localhost;initial catalog=EFDB2;persist security info=True;user id=sa;password=123456;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" />
3. 代碼實踐
有兩種插入方式,一種是循序漸進的每一個字段 內存表和數據表進行映射,這個狀況無須名稱一致,只要映射正確便可。另一種方式是,直接調用下面的封裝方法便可,這種要求內存表中字段和數據庫表中的字段名稱必須徹底一致,一一對應,這樣就省去了方法一 中一一匹配映射的繁瑣步驟了。
1 public class SqlBulkCopyTest 2 { 3 public static void TestSqlBulkCopy() 4 { 5 //一. 構造DataTable結構而且給其賦值 6 //1.定義與目標表的結構一致的內存表 排除自增id列 7 DataTable dtSource = new DataTable(); 8 //列名稱若是和目標表設置爲同樣,則後面能夠不用進行字段映射 9 dtSource.Columns.Add("id"); 10 dtSource.Columns.Add("t21"); 11 dtSource.Columns.Add("t22"); 12 //2. 向dt中增長4W條測試數據 13 DataRow dr; 14 for (int i = 0; i <40000; i++) 15 { 16 // 建立與dt結構相同的DataRow對象 17 dr = dtSource.NewRow(); 18 dr["id"] = Guid.NewGuid().ToString("N"); 19 dr["t21"] = "Name" + i; 20 dr["t22"] = "Address" + i; 21 // 將dr追加到dt中 22 dtSource.Rows.Add(dr); 23 } 24 //二.將內存表dt中的4W條數據一次性插入到t_Data表中的相應列中 25 System.Diagnostics.Stopwatch st = new System.Diagnostics.Stopwatch(); 26 st.Start(); 27 string connStr = ConfigurationManager.ConnectionStrings["CodeFirstModel2"].ToString(); 28 29 #region 01-循序漸進一一對應 30 //{ 31 // using (SqlBulkCopy copy = new SqlBulkCopy(connStr)) 32 // { 33 // //1 指定數據插入目標表名稱 34 // copy.DestinationTableName = "TestTwo"; 35 36 // //2 告訴SqlBulkCopy對象 內存表中的 字段和目標表中的字段 對應起來(這裏有多個重載,也能夠用索引對應) 37 // //前面是內存表,後面是目標表即數據庫中的字段 38 // copy.ColumnMappings.Add("id", "id"); 39 // copy.ColumnMappings.Add("t21", "t21"); 40 // copy.ColumnMappings.Add("t22", "t22"); 41 42 // //3 將內存表dt中的數據一次性批量插入到目標表中 43 // copy.WriteToServer(dtSource); 44 // } 45 //} 46 47 #endregion 48 49 #region 02-調用封裝 50 { 51 AddByBluckCopy(connStr, dtSource, "TestTwo"); 52 } 53 #endregion 54 55 st.Stop(); 56 Console.WriteLine("數據插入成功,總耗時爲:" + st.ElapsedMilliseconds + "毫秒"); 57 58 } 59 60 /// <summary> 61 /// 海量數據插入方法 62 /// (調用該方法須要注意,DataTable中的字段名稱必須和數據庫中的字段名稱一一對應) 64 /// </summary> 65 /// <param name="connectstring">數據鏈接字符串</param> 66 /// <param name="table">內存表數據</param> 67 /// <param name="tableName">目標數據的名稱</param> 68 public static void AddByBluckCopy(string connectstring,DataTable table, string tableName) 69 { 70 if (table != null && table.Rows.Count > 0) 71 { 72 using (SqlBulkCopy bulk = new SqlBulkCopy(connectstring)) 73 { 74 bulk.BatchSize = 1000; 75 bulk.BulkCopyTimeout = 100; 76 bulk.DestinationTableName = tableName; 77 bulk.WriteToServer(table); 78 } 79 } 80 } 81 }
4. 性能測試的結論
根據上述的數據測試能夠看出來,SqlBulkCopy在處理大數據量插入上速度很是快,甚至比付費的插件Z.EntityFramework.Extensions都要快,因此值得參考和推薦。
既然SqlBulkCopy解決大數據量的插入問題,那麼刪除和更新怎麼辦呢? 詳見 第二十三節: EF性能篇(三)之基於開源組件 Z.EntityFrameWork.Plus.EF6解決EF性能問題
!