[Asp.net] 使用EF建立大量資料(針對TransactionScope測試)

  • 334
  • 0
  • 2022-05-31

[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://blog.yowko.com/entityframework-bulk-insert/?fbclid=IwAR3XSUBJsBwXtcHOvFekgY553BjBhQVzM5BDWEZ2xlWp9GuUiD7t-Dxb3DU

完整程式

https://github.com/charley85470/EFMultiCommitTest/tree/master/EFMultiCommitTest

 

 

Write By Charley Chang 


新手發文,若有錯誤還請指教,
歡迎留言或Mail✉給我

創用 CC 授權條款


本著作係採用創用 CC 姓名標示-非商業性-相同方式分享 4.0 國際 授權條款授權.