C#之EF 优化篇之EF优化

1.基本优化方式:

  • 避免使用大的数据库事务,尽量控制在有需求是打开,不需要是及时关闭,因为会锁定资源
  • 批量插入表数据,尽量避免在同一DBContext下做多次SavceChange操作
  • 若有大批数据需要插入表,尽量采用单表集中插入后再操作后续集,避免插入一条数据savaChange一次
  • 读取数据尽量按批量读取,避免取得一条数据读取一次
  • 查询100次单条记录与一次性查询100条记录是有很大差别的

2.LInq的真假分页

query.ToList().Skip((PageIndex - 1) * PageSize).Take(PageSize);
query.Skip((PageIndex - 1) * PageSize).Take(PageSize).ToList();
  • 第一条(假分页)
    先把数据查询出来,放到内存中;转换成List;从List中进行分页操作,查询出结果
  • 第二条(真分页)
    将参数传到数据库,生成分页sql语句,然后再查询出结果

3.合理使用EF的加载方式

4.事务尽量简短

  • 尽量要把与事务无关的东西放到事务外执行,如果让一个事务的执行时间过长,很容易引起资源死锁的问题,当用压力测时,马上就出现资源被锁的错误。
  • 查询语句或者其他事务外的语句

5.NoTracking的使用
若查询出的实体不需要删除和修改,使用NoTracking

 using (var context = new MyDbContext())
    { 
         var people = context.People
         .Where(p => p.PersonID >100)
         .AsNoTracking()
         .ToList();
    }

有时我们的实体只需要显示,无需更新,所以为了提高性能,我们不需要实体被EF context追踪。此时可以使用NoTracking的查询来得到实体,这样实体的状态会是Detached状态

6.SQL Server Profiler的使用
对于逻辑相对复杂的查询,要随时监控生成的Sql语句
毕竟EF生成的语句,往往比我们生成的语句更加复杂,这个时候我们就要考虑是否通过其他方式来提高性能。比如自己写原生的sql语句,有时候原生SQL语句是更好的选择。另外我们要善于使用SQL Server Profiler这个工具,实时监控生成的sql语句。

7.EF的根源拓展

#region 按条件查询:LoadItems(Func<T, bool> whereLambda)
        /// <summary>
        /// 按条件查询
        /// </summary>
        /// <param name="whereLambda">lambda表达式</param>
        /// <returns>IQueryable 泛型集合</returns>
        public IQueryable<T> LoadItems(Func<T, bool> whereLambda)
        {
            return MyBaseDbContext.Set<T>().Where(whereLambda).AsQueryable();
        }
 #endregion

方法的参数whereLambda,其类型为Func<T, bool> ,在调用LoadItems方法时,通过SQL Server Profiler检测生成的sql语句,你会发现它只生成了一条查询全部结果的语句。然后通过一步步断点调试发现,将数据全部加载完毕后,还会根据查询条件whereLambda进行很多次的循环,才能把最终结果返回。并且当调用带条件参数的查询方法时,都会遇到这个问题。不过当发现问题之后,基本也就能解决问题了。随后我们发现了与Func<TObject, bool> 非常相似的类型Expression<Func<TObject, bool>>

解决方案

  • Expression<Func<TObject, bool>>为表达式类型,它会带上查询条件一并生成sql语句,将查询结果返回,大大提高查询效率
    Lambda表达式作为表达式树形式的数据。

修改后代码

#region 按条件查询:
LoadItems(Expression<Func<T, bool>> whereLambda)
        /// <summary>
        /// 按条件查询
        /// </summary>
        /// <param name="whereLambda">lambda表达式</param>
        /// <returns>IQueryable 泛型集合</returns>
        public IQueryable<T> LoadItems(Expression<Func<T, bool>> whereLambda)
        {
            return MyBaseDbContext.Set<T>().Where(whereLambda).AsQueryable();
        }
#endregion

8.其他:

  • Include()方法的使用
    • 通过edmx中表的导航属性名字,来查询出关联的表的数据
var students= conext.Person.Include("Students");
//就是在person的表中有Students这个Propetry连接另外一个表​
  • 如果需要查出关联表的关联,则在Include中可以用.连接
var students= conext.Person.Include("Students.Student_Course.Courses");
//查询Person对象的也查出来了student,course的信息
  • 也可以通过=>的方式

  • 基本

	 var blogs1 = context.Blogs
                        .Include(b => b.Posts)
                        .ToList();
  • 进阶
var blogs1 = context.Blogs
                        .Include(b => b.Posts.Select(p => p.Comments))
                        .ToList();
  • Query()方法的使用(显式加载):1

有过滤条件时

       static void QueryLodgingDistance()
         {
             using (var ctx = new BreakAwayContext())
             {
                 var france = ctx.Destinations.First(t => t.Country == "法国");
                 var lessTenMilesLodgings = ctx.Entry(france)
                                             .Collection(t => t.Lodgings)
                                             .Query()
                                             .Where(t => t.MilesFromNearestAirport < 10);
                 foreach (var lodging in lessTenMilesLodgings)
                 {
                     Console.WriteLine(lodging.Name);
                 }
             }
         }

当有关联,有需要做Count()操作时,可以用Query方法。

using (var context = new BloggingContext())
{
    var blog = context.Blogs.Find(1);
    // Count how many posts the blog has.
    var postCount = context.Entry(blog)
                           .Collection(b => b.Posts)
                           .Query()
                           .Count();
}

EF学习和使用(八)你必须知道的效率问题根源之Expression与Func


  1. https://www.cnblogs.com/nianming/archive/2013/01/09/2846952.html ↩︎

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值