###### tags: `Entity Framework` # 大批量Create處理時間議題與Query追蹤議題 ## 一、大批量Create處理時間議題 ### a.情境 近期在使用EF新增資料時遇到一次要插入大量資料時的需求(一次約快1w5千筆)。因為EF Bulk Insert要錢(第三方套件),顧很單純使用DbContext Add,插入時間要將近30秒。 ### [Root Casue](https://docs.microsoft.com/zh-tw/ef/ef6/saving/change-tracking/auto-detect-changes) EF POCO在做異動時,會呼叫DetectChanges()比對所有entry集合中每一個Property的新就值,顧會造成在大量操作時拉長時間。以下為會呼叫DetectChanges()的方法 - DbSet.Find - DbSet.Local - DbSet.Add - DbSet.AddRange - DbSet.Remove - DbSet.RemoveRange - DbSet.Attach - DbContext.SaveChanges - DbCoNtext.GetValidationErrors - DbContext.Entry - DbChangeTracker.Entries ### b.解法 根據上述原因,若要縮短大量資料建立時間有兩種方法 - 使用AddRange - 直接使用AddRange一次性加入所有資料,會比起每次Add都要呼叫一次DetectChanges()時間來的短。 - Configuration.AutoDetectChangesEnabled屬性設置成false - 直接將AutoDetectChangesEnabled設成false,Add完後再設為true。 ### c.測試結果 實測結果如下,12544筆資料存取時間 - Add : 34s - AddRange : 13s - AutoDetectChangesEnabled fasle : 13s ## 二、[Query追蹤議題](https://docs.microsoft.com/zh-tw/ef/core/querying/tracking#tracking-queries) For處理大批量Create處理時間議題也稍微查一下Query部分,發現EF查詢預設有Tracking的設計。稍微寫一下Testing Code如下 ![](https://i.imgur.com/grQZPx1.png) 操作步驟為 - Step1: Context1 索取Mario資料 - Step2: Context2 新增一筆Test資料 - Step3: Context1 修改Mario資料為Jack 結果如下 ![](https://i.imgur.com/O6MYb0L.png) 可以發現Context1查覺到筆數有增加,但Context2獨到的Name能然為舊值。 因為Context2拿取了Cache資料內容,第二次Query並沒從DB讀取。所以讀到的值仍為舊值。此時如果我們將Context2第二查詢改為 ```= dbContext2.TestRecord.AsNoTracking().SingleOrDefault(x => x.Id == 1).Name ``` 此時讀到的值則就會是Context1改過的Name值Jack,因此如果在唯讀的使用情境下,使用不追蹤查詢可以加快查詢速度。(待實測)