EF大數據批量添加性能問題(續)

昨天在園子裏發了一篇如題的文章EF大數據批量添加性能問題,就引來一大堆的吐槽,我認爲知識就應該這樣分享出來,否則總覺得本身很了不得;再說說昨天那篇文章,不少自認爲很牛逼的人都評論說把SaveChanges()放在for循環外面,我不知道他們有沒有親自去嘗試過,反正我嘗試了,然而並沒什麼卵用。html

下面是我按照他們說的進行更改後的代碼:性能

 1  public ActionResult Add(ItemDetails entity)
 2         {
 3             var sw = new Stopwatch();
 4             var count = 0;
 5             //var counts = 0;
 6             sw.Start();
 7             using (var db = new ShoppingDBConn())
 8             {
 9                 for (var i = 0; i < 10000; i++)
10                 {
11                     var data = new ItemDetails
12                     {
13                         AddedBy = entity.AddedBy,
14                         Description = entity.Description,
15                         Image_Name = entity.Image_Name,
16                         Item_Name = entity.Item_Name,
17                         Item_Price = entity.Item_Price
18                     };
19                     db.ItemDetails.Add(data);
20                 }
21                 count = db.SaveChanges();
22             }
23             sw.Stop();
24             var date = sw.Elapsed;
25             return Json(string.Format("總耗時:{0},添加數量:{1}", date, count));
26         }

運行耗時:大數據

 

 

再看看AddRange方式:優化

 1         public ActionResult Add(ItemDetails entity)
 2         {
 3             var sw = new Stopwatch();
 4             var count = 0;
 5             //var counts = 0;
 6             sw.Start();
 7             using (var db = new ShoppingDBConn())
 8             {
 9                 var list = new List<ItemDetails>();
10                 for (var i = 0; i < 10000; i++)
11                 {
12                     list.Add(new ItemDetails
13                     {
14                         AddedBy = entity.AddedBy,
15                         Description = entity.Description,
16                         Image_Name = entity.Image_Name,
17                         Item_Name = entity.Item_Name,
18                         Item_Price = entity.Item_Price
19                     });
20                 }
21                 db.ItemDetails.AddRange(list);
22                 count = db.SaveChanges();
23             }
24             sw.Stop();
25             var date = sw.Elapsed;
26             return Json(string.Format("總耗時:{0},添加數量:{1}", date, count));
27         }

 

耗時狀況:spa

 

 

不過還好有幾位給出了很好的建議,用SqlBulkCopy,下面是優化後的代碼,比上面任何一種都要快好幾倍:pwa

 1         public void BulkInsertAll<T>(IEnumerable<T> entities)  
 2         {
 3             entities = entities.ToArray();
 4             var cons=new ShoppingDBConn();
 5             string cs = cons.Database.Connection.ConnectionString;
 6             var conn = new SqlConnection(cs);
 7             conn.Open();
 8 
 9             Type t = typeof(T);
10 
11             var bulkCopy = new SqlBulkCopy(conn)
12             {
13                 DestinationTableName = t.Name
14             };
15 
16             var properties = t.GetProperties().Where(EventTypeFilter).ToArray();
17             var table = new DataTable();
18 
19             foreach (var property in properties)
20             {
21                 Type propertyType = property.PropertyType;
22                 if (propertyType.IsGenericType &&
23                     propertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
24                 {
25                     propertyType = Nullable.GetUnderlyingType(propertyType);
26                 }
27 
28                 table.Columns.Add(new DataColumn(property.Name, propertyType));
29             }
30 
31             foreach (var entity in entities)
32             {
33                 table.Rows.Add(properties.Select(
34                   property => GetPropertyValue(
35                   property.GetValue(entity, null))).ToArray());
36             }
37 
38             bulkCopy.WriteToServer(table);
39             conn.Close();
40         }
41 
42         private bool EventTypeFilter(System.Reflection.PropertyInfo p)
43         {
44             var attribute = Attribute.GetCustomAttribute(p,
45                 typeof(AssociationAttribute)) as AssociationAttribute;
46 
47             if (attribute == null) return true;
48             if (attribute.IsForeignKey == false) return true;
49 
50             return false;
51         }
52 
53         private object GetPropertyValue(object o)
54         {
55             if (o == null)
56                 return DBNull.Value;
57             return o;
58         }

調用該方法: code

 1  public ActionResult Add(ItemDetails entity)
 2         {
 3             var sw = new Stopwatch();
 4             var count = 0;
 5             //var counts = 0;
 6             sw.Start();
 7             using (var db = new ShoppingDBConn())
 8             {
 9                 var list = new List<ItemDetails>();
10                 for (var i = 0; i < 10000; i++)
11                 {
12                     list.Add(new ItemDetails
13                     {
14                         AddedBy = entity.AddedBy,
15                         Description = entity.Description,
16                         Image_Name = entity.Image_Name,
17                         Item_Name = entity.Item_Name,
18                         Item_Price = entity.Item_Price
19                     });
20                     count++;
21                 }
22                 BulkInsertAll(list);
23             }
24             sw.Stop();
25             var date = sw.Elapsed;
26             return Json(string.Format("總耗時:{0},添加數量:{1}", date, count));
27         }

總耗時狀況: orm

比上一篇的拼接SQL都要快好幾倍,在此很感謝@_April htm

相關文章
相關標籤/搜索