EF查询之性能优化

关于EF性能优化的讲解,推荐阅读下面的博文

1.EF查询之性能优化:https://www.cnblogs.com/eggTwo/p/5959207.html
2.Entity Framework 延伸系列目录:

  • a.Entity Framework 延伸系列目录
  • b.采用EntityFramework.Extended 对EF进行扩展(Entity Framework 延伸系列2)
  • c.EntityFramework执行存储过程中遇到的那些坑
  • d.EntityFramework的多种记录日志方式,记录错误并分析执行时间过长原因(系列4)
    https://www.cnblogs.com/GuZhenYin/p/5482288.html

一、EF性能优化

1.延迟加载的开关
  • a.默认情况延迟加载是开启的,延迟加载的开启方式有两种:
  • (1)第一种是在dbcontext中设置
  public MyDbContext(System.Data.Common.DbConnection oConnection)
            : base(oConnection, true)
 {
            this.Configuration.LazyLoadingEnabled = true;         
  }
  • (2)第二种是在使用DbContext的时候设置
using (var db = new Core.EF.MyDbContext())
{
                    db.Configuration.LazyLoadingEnabled = false;
                    var classes= db.T_Student.Where(c => true).FirstOrDefault();
                    int a = 3;
}
  • b.当我们不需要使用子表的时候可以关闭延迟加载
using (var db = new Core.EF.MyDbContext())
{
                    db.Configuration.LazyLoadingEnabled = false;
                    var classes= db.T_Student.Where(c => true).FirstOrDefault();
                    int a = 3;
}

  • c.当我们需要使用子表的时候可以打开延迟加载
using (var db = new Core.EF.MyDbContext())
{
                    db.Configuration.LazyLoadingEnabled = true;
                    var classes= db.T_Student.Where(c => true).FirstOrDefault();
                    int a = 3;
}

2.延迟加载时使用Include提高性能
  • 使用inlude的两大前提
  • 1.开启延迟加载
  • 2.在使用Include的类上using System.Data.Entity
(1)不使用include的情况
#region 不使用include的情况,查询了6次
                    //当我们不需要使用子表的数据时,我们可以选择关闭延迟加载
                    db2.Configuration.LazyLoadingEnabled = true;//延迟加载
                    var students = db2.T_Student.Where(c=>true).Take(5).ToList();
                    foreach (var item in students)
                    {
                        var c = item.T_Classes;
                    }
#endregion

看出:查询了6次(1次T_Student,5次T_Classes)

(2)使用include的情况
#region 使用include的情况,只查询了一次(T_Student和T_Classes进行了连表查询)
                    //当我们不需要使用子表的数据时,我们可以选择关闭延迟加载
                    db2.Configuration.LazyLoadingEnabled = true;//延迟加载
                    var students1 = db2.T_Student.Where(c => true).Take(5).Include(c => c.T_Classes).ToList();
                    foreach (var item in students1)
                    {
                        var c = item.T_Classes;
                    }
#endregion


看出:查询了1次(T_Student和T_Classes连表查询)

3.AsNoTracking提高查询性能
  var student3 = db2.T_Student.Where(c => c.Name == "李四50").Take(5).ToList();
  var student4 = db2.T_Student.Where(c => c.Name == "李四50").Take(5).AsNoTracking().ToList();
  • AsNoTracking的作用就是在查询的时候不做跟踪,这样查询的会更快,但是这样做会有一个缺陷:不能对查询的数据做修改操作
4.多字段排序
     //错误的写法:age的排序会把name的排序冲掉
     var student5 = db2.T_Student.Where(c => c.Name == "李四50").OrderBy(c => c.Name).OrderBy(c => c.Age).AsNoTracking().ToList();
    //正确的写法:
    var student6 = db2.T_Student.Where(c => c.Name == "李四50").OrderBy(c => c.Name).ThenBy(c => c.Age).AsNoTracking().ToList();

5.EF中使用sql
                    ///*
                    //  这种写法还支持将sql语句查询的结果集(DataSet和DataTable)
                    //  直接转换成对应的强类型集合(List<T>)

                    // */

                    //db2.Database.SqlQuery<T>("sql","parameters");

                    ///*
                    // 如果使用db.Database.SqlQuery<T>("sql语句")进行分页查询
                    // 的话,要注意避免内存分页
                    // */

                    ///*
                    // 错误的写法,内存分页
                    // 如果使用db.Database.SqlQuery<T>("sql语句")进行分页查询的话,要注意避免内存分页
                    // */
                    //var pageSize = 15;
                    //var pageIndex = 2;
                    //db2.Database.SqlQuery<T>("select * from T_Student").OrderByDescending(c=>c.CreateTime).Skip(pageSize*(pageIndex -1)).Take(pageSize).ToList();
                    ////这种写法会导致在内存中分页


                    ///*
                    // 正确的写法
                    // */
                    //string sql = "select * from T_Student";
                    //string orderBy = "CreateTime desc";
                    //StringBuilder sb = new StringBuilder();
                    //sb.Append(string.Format(@"select * from(select *,row_number() over (order by {0} as row from(", orderBy));
                    //sb.Append(sql);
                    //sb.Append(@") as t)as s where s.row between " +(pageIndex * pageSize -pageSize +1) + " and " +(pageIndex *pageSize));
                    //var list = db2.Database.SqlQuery<T>(sb.ToString()).ToList();

6.存在性之Any
              //测试班级表中是否包含'高中二班4'
              bool a = db2.T_Classes.Where(c => c.Name == "高中二班4").Count() > 0;
              bool b = db2.T_Classes.Count(c => c.Name == "高中二班4") > 0;
              bool e = db2.T_Classes.Where(c => c.Name == "高中二班4").FirstOrDefault() != null;
              bool d = db2.T_Classes.Any(c => c.Name == "高中二班4");

              //一共上述4种写法
              //结果:第1种写法和第二种写法生成的sql语句是一样的,
              //第三种写法和第四种写法的耗时明显比第一种写法少???这个实际看到的是多!!!,还没研究明白!!!!!!!!

7.多表查询
 ////等值连接Lambda写法
                    //var result1 = db2.T_Classes.Where(t => t.Money == 2000).Join(db2.T_Student, c => c.ID,
                    //    s => s.ClassesID, (c, s) => new {
                    //        CName = c.Name,
                    //        SName = s.Name
                    //    }).ToList();
                    ////等值连接Linq写法
                    //var resut2 = (from c in db2.T_Classes
                    //              join s in db2.T_Student
                    //              on c.ID equals s.ClassesID
                    //              where c.Money == 2000
                    //              select new
                    //              {
                    //                   CName =c.Name,
                    //                   SName = s.Name
                    //              }).ToList();
                    ////可以看出以上两种写法生成的sql语句是一样的



                    ////左(右)连接的写法

                    ////左外连接的写法
                    //var results = (from c in db2.T_Classes.Where(a => a.Money == 2000)
                    //               join s in db2.T_Student on c.ID equals s.ClassesID into temp

                    //               //临时表
                    //               from t in temp.DefaultIfEmpty()
                    //               select new
                    //               {
                    //                   CName = c.Name,
                    //                   SName = t.Name

                    //               }).ToList();

8.分页查询封装
                     //单条件排序
                    var r1 = Repository.GetPagedEntitys<T_Classes, int>(db2, 1, 20, c => c.Deleted == false, false, c => c.ID);
                    //多条件排序
                    var r2 = Repository.GetPagedEntitys<T_Classes, int, bool>(db2,1,20,c=>c.Deleted ==false,false,c=>c.ID,true,c=>c.Deleted);
                    //sql查询转强类型
                    var r3 = Repository.GetPagedEntitysBySqlWhere<T_Classes>(db2, 1, 20, "and Deleted=0", "ID DESC");
                    //纯sql操作
                    var r4 = Repository.GetPagedTable(db2,1,20,"select * from T_Classes where Deleted=0","ID DESC");

9.Expressions扩展
/**
                    条件的拼接(当满足某个固定条件时才把对应的条件拼接出来) 
                    */

                    //原始的写法:
                    //模拟一系列条件
                    string name = "李四0";
                    int age = 0;
                    int pageSize = 20;
                    int pageIndex = 1;
                    ////原始写法如下:
                    //var query = db2.T_Student.Where(c=>c.Deleted == false);
                    //if (!string.IsNullOrEmpty(name))
                    //{
                    //    query = query.Where(c=>c.Name.Contains(name));
                    //}
                    //if (age !=0)
                    //{
                    //    query = query.Where(c => c.Age == age);
                    //}

                    //var list = query.OrderByDescending(c => c.ID).Skip(pageSize * (pageIndex - 1)).Take(pageSize).ToList();

                    //无法和封装的分页类进行集成,返回的数据只有列表集合,没有总页数和总记录数



                    //所以对Linq.Expressions进行扩展                  


                    //多条件查询 +分页的极速简单写法(强烈推荐写法)

                    //利用扩展的Linq的写法
                    Expression<Func<T_Student, bool>> exp = c => true;
                    if (!string.IsNullOrEmpty(name))
                    {
                        exp = exp.And(c => c.Name.Contains(name));
                    }
                    if (age != 0)
                    {
                        exp = exp.And(c => c.Age == age);
                    }
                    var r9 = Repository.GetPagedEntitys<T_Student, int>(db2, 1, 20, exp, false, c => c.ID);

以上说明是参考: https://www.cnblogs.com/eggTwo/p/5959207.html 这位大牛博主的博文做的,就附上对应demo下载地址,供大家学习:
附:[EF性能优化demo]

猜你喜欢

转载自www.cnblogs.com/newcapecjmc/p/12845377.html