第十四节: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 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
 
posted @ 2020-01-14 21:40  Yaopengfei  阅读(1710)  评论(5编辑  收藏