[Asp.net] 使用EF建立大量資料
前言
因實務上有遇到以EF建立大量資料的狀況,
根據網友分享的文章,
其測試指出『批次對Context進行SaveChange並dispose』的效能相對較佳,
但假如我要保證此次資料必須完整Commit(當其中一筆資料沒有成功就全部Rollback),
則此方法似乎不太能符合需求(因為dispose後就不能Rollback了),
於是需要在最外層包上TransactionScope,
其程式會如下面所示
Console.WriteLine("每1000筆Save一次並ClearContext(維持同一筆交易)");
processTime.Start();
var per = 1000;
var times = total / per;
Console.Write("times ");
using (TransactionScope ts = new TransactionScope(TransactionScopeOption.RequiresNew, new TimeSpan(0, 10, 0)))
{
for (int i = 0; i < times; i++)
{
using (var ctx = new ProjDBEntities())
{
for (int j = 0; j < per; j++)
{
ctx.Customer.Add(new Customer());
}
ctx.SaveChanges();
}
Console.Write(" " + i);
}
ts.Complete();
Console.WriteLine();
}
processTime.Stop();
Console.WriteLine("共建立 " + total + " 筆資料,耗時 " + processTime.Elapsed.TotalMilliseconds.ToString() + "ms");
processTime.Reset();
測試效能差異
在包了TransactionScope後我有另一個疑問
是否會因為TransactionScope而影響原本的效能?
於是做了以下測試
Stopwatch processTime = new Stopwatch();
#region 每1000筆Save一次並Clear Context
{
Console.WriteLine("每1000筆Save一次並ClearContext");
processTime.Start();
var per = 1000;
var times = total / per;
Console.Write("times ");
for (int i = 0; i < times; i++)
{
using (var ctx = new ProjDBEntities())
{
for (int j = 0; j < per; j++)
{
ctx.Customer.Add(new Customer());
}
ctx.SaveChanges();
}
Console.Write(" " + i);
}
Console.WriteLine();
processTime.Stop();
Console.WriteLine("共建立 " + total + " 筆資料,耗時 " + processTime.Elapsed.TotalMilliseconds.ToString() + "ms");
processTime.Reset();
}
#endregion
#region 每1000筆Save一次並Clear Context(維持同一筆交易)
{
Console.WriteLine("每1000筆Save一次並ClearContext(維持同一筆交易)");
processTime.Start();
var per = 1000;
var times = total / per;
Console.Write("times ");
using (TransactionScope ts = new TransactionScope(TransactionScopeOption.RequiresNew, new TimeSpan(0, 10, 0)))
{
for (int i = 0; i < times; i++)
{
using (var ctx = new ProjDBEntities())
{
for (int j = 0; j < per; j++)
{
ctx.Customer.Add(new Customer());
}
ctx.SaveChanges();
}
Console.Write(" " + i);
}
ts.Complete();
Console.WriteLine();
}
processTime.Stop();
Console.WriteLine("共建立 " + total + " 筆資料,耗時 " + processTime.Elapsed.TotalMilliseconds.ToString() + "ms");
processTime.Reset();
}
#endregion
如上所示
我分別建立了有TransactionScope與無TransactionScope的程式
並以Stopwatch計算各自的耗時
其結果如下
看起來差異並不大
但這是只有異動同一張Table的資料
假如要異動多張Table呢?
調整程式如下
using (TransactionScope ts = new TransactionScope(TransactionScopeOption.RequiresNew, new TimeSpan(0, 10, 0)))
{
for (int i = 0; i < times; i++)
{
using (var ctx = new ProjDBEntities())
{
for (int j = 0; j < per; j++)
{
ctx.Customer.Add(new Customer());
}
ctx.SaveChanges();
}
using (var ctx = new ProjDBEntities())
{
for (int j = 0; j < per; j++)
{
ctx.UserMain.Add(new UserMain());
}
ctx.SaveChanges();
}
Console.Write(" " + i);
}
ts.Complete();
Console.WriteLine();
}
最後執行出來的結果
似乎包了TransactionScope後影響的效能並不會太大
以上是我測試後得到的結果
如果有其他大大測出不一樣的狀況
歡迎提出一起交流
感謝!!!
PS.不過若資料量真的非常大,TransactionScope會有Timeout的可能(MaxTimeout似乎只有10min),這又是另外一回事了...
引用
完整程式
https://github.com/charley85470/EFMultiCommitTest/tree/master/EFMultiCommitTest
Write By Charley Chang
新手發文,若有錯誤還請指教,
歡迎留言或Mail✉給我
本著作係採用創用 CC 姓名標示-非商業性-相同方式分享 4.0 國際 授權條款授權.