第十四節:EF Core性能優化


1.使用DbContext池

  在Core Mvc中,如果使用 AddDbContextPool 方法,那么在控制器請求 DbContext 實例時,我們會首先檢查池中有無可用的實例。 請求處理完成后,實例的任何狀態都將被重置,並且實例本身會返回池中。 從概念上講,此方法類似於 ADO.NET 連接池的運行原理,並具有節約 DbContext 實例初始化成本的優勢。

 eg:

 services.AddDbContextPool<BloggingContext>( options => options.UseSqlServer(connectionString));

2.優先使用異步方法

  EF Core 中提供了很多形如 xxxAsync 的異步方法,推薦使用這些方法提高吞吐量和性能,減少不必要的延時等待。

3.多活動結果集連接復用

  多活動結果集 (MARS) 是一項允許對單個連接執行多個批處理的功能。 在以前的版本中,在單個連接上一次只能執行一個批處理。 使用 MARS 執行多個批處理並不意味着同時執行操作。 在連接字符串中添加:MultipleActiveResultSets=True 即可啟用 MARS 特性。

詳細見:https://docs.microsoft.com/zh-cn/dotnet/framework/data/adonet/sql/enabling-multiple-active-result-sets

4.批處理語句

  EFCore中有一個重大改進,就是批處理,比如向數據庫中增加n條數據(n>3),會組合成一次請求訪問數據庫(而在以前的EF中,不是批處理,增加幾條,則會訪問幾次)。

 注:操作數據條數 <=3 的時候,不會批處理,還是分多次請求,只有>3,才會批處理。

PS:可以手動設置批處理的條數MaxBatchSize,默認值很大optionsBuilder.UseSqlServer("Server=localhost;Database=EFDB01;User ID=sa;Password=123456;", b => b.MaxBatchSize(10));

(1). 增加

1                   //1.增加 (3條及以下不合並,3條以上合並)
2                     for (int i = 0; i < 5; i++)
3                     {
4                         dbContext.Add(new T_UserInfor() { id = Guid.NewGuid().ToString("N"), userAge = i, addTime = DateTime.Now });
5                     }
6                     int count = dbContext.SaveChanges();

(2). 修改

1                     //2.修改(3條及以下不合並,3條以上合並)
2                     var list = dbContext.T_UserInfor.Take(5).ToList();
3                     foreach (var item in list)
4                     {
5                         item.userSex = "男111";
6                     }
7                     int count2 = dbContext.SaveChanges();

(3). 混合操作

 1                   //3.插入、更新、刪除的混合操作 (3條及以下不合並,3條以上合並)
 2                     var list3 = dbContext.T_UserInfor.Take(2).ToList();
 3                     //增加
 4                     for (int i = 0; i < 2; i++)
 5                     {
 6                         dbContext.Add(new T_UserInfor() { id = Guid.NewGuid().ToString("N"), userAge = i, addTime = DateTime.Now });
 7                     }
 8                     //更新
 9                     foreach (var item in list3)
10                     {
11                         item.userAge = 12;
12                     }
13                     //刪除
14                     dbContext.Entry(list3.Take(1).FirstOrDefault()).State = EntityState.Deleted;
15                     int count3 = dbContext.SaveChanges();

5.關閉狀態追蹤

  跟蹤行為決定了 EF Core 是否將有關實體實例的快照信息保留在其更改跟蹤器中。 如果已跟蹤某個實體,則該實體中檢測到的任何更改都會在 SaveChanges() 期間永久保存到數據庫。當決定只查詢數據,不更改數據時,非跟蹤查詢十分有用,非跟蹤查詢的執行會更快,因為無需為查詢實體設置快照跟蹤信息。 如果不需要更新從數據庫中檢索到的實體,則應優先使用非跟蹤查詢。

(1).單體查詢關閉:AsNoTracking()

(2).整個上下文關閉:context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;

6.關閉狀態同步

  當從數據庫進行查詢數據時,上下文便捕獲了每個實體屬性的快照(數據庫值,原始值,當前值),當調用SaveChanges 時,在內部會自動調用 DetectChanges 方法,此方法將掃描上下文中所有實體,並比較當前屬性值和存儲在快照中的原始屬性值,如果被找到的屬性值發生了改變,此時EF將會與數據庫進行交互,進行數據更新。會導致自動調用 DetectChanges 方法: Find、Local、Remove、Add、Update、Attach、SaveChanges 和Entry 等。 但是,自動同步狀態會頻繁調用,可手動關閉以上方法的自動同步,當數據都修改好后,一次性手動同步。

關閉:context.ChangeTracker.AutoDetectChangesEnabled = false;

開啟:context.ChangeTracker.DetectChanges();

7.使用 EF.Functions.xxx 進行查詢

(1).使用 EF.Functions.Like進行模糊查詢要比 StartsWith、Contains 和 EndsWith 方法生成的SQL語句性能更優。

A. Contains語句,生成的sql為:

  var data3 = dbContext.T_UserInfor.Where(u => u.userName.Contains("p")).ToList();

用的是charindex

B. EF.Functions.Like語句生成的sql為:

  var data1 = dbContext.T_UserInfor.Where(u => EF.Functions.Like(u.userName, "%p%")).ToList();
  //或者
  var data2 = (from p in dbContext.T_UserInfor
               where EF.Functions.Like(p.userName, "%p%")
               select p).ToList();

用的是Like

PS:在傳統的.Net中,還有種用法 SqlMethods,詳見:https://www.cnblogs.com/yaopengfei/p/11805980.html

(2).還有EF.Functions.DateDiffDay (DateDiffHour、DateDiffMonth),求天、小時、月之間的數量

PS:在EF Core中StartsWith、Contains和EndsWith模糊查詢實際分別被解析成為Left、CharIndex和Right,而不是Like,而EF.Functions.Like會解析成Like語句。

詳見:https://www.cnblogs.com/tdfblog/p/entity-framework-core-like-query.html

 

8.DbFunctionAttribute 標量函數

  EF Core 支持映射數據庫中定義的函數,可以在 LINQ 查詢中使用,該功能支持將數據庫標量函數映射到方法存根,使其可用於 LINQ 查詢並轉換為 SQL。 在 DbContext 上聲明靜態方法,並使用 DbFunctionAttribute 對其批注.

 

 

 

 

 

 

!

  • 作       者 : Yaopengfei(姚鵬飛)
  • 博客地址 : http://www.cnblogs.com/yaopengfei/
  • 聲     明1 : 本人才疏學淺,用郭德綱的話說“我是一個小學生”,如有錯誤,歡迎討論,請勿謾罵^_^。
  • 聲     明2 : 原創博客請在轉載時保留原文鏈接或在文章開頭加上本人博客地址,否則保留追究法律責任的權利。
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM