• 第十四节: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 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
     
  • 相关阅读:
    模电电路分析
    正式答辩提问
    Dockerfile
    Docker常用命令
    docker镜像与容器
    Docker容器与容器数据
    docker命令自动安装
    Docker与虚拟机
    Java Lambda表达式 Stream
    Java Lambda表达式
  • 原文地址:https://www.cnblogs.com/yaopengfei/p/12194230.html
Copyright © 2020-2023  润新知