EF学习和使用(七)EF性能优化篇

时间:2021-03-09 16:44:29

自从ITOO平台旗下的评教系统问世之后,其性能问题引起了轩然大波。CPU占用过高,页面反映速度超慢,根本无法正常使用,为此我们专门成立一个性能优化小队,去研究为什么系统性能这么低,怎么优化性能?


框架中用到了EntityFramework,WCF,EasyUI等技术,所以我们大胆猜测可能是这三方面影响了系统的整体性能。经过一段时间的研究和实践,发现我们在使用EF的过程中,由于经验原因对EF的不了解,不经意写的一些代码都会在一定程度上影响系统的性能。


下面总结了一些在使用EF的过程中应当特别注意的地方,避免大家再走弯路。


1、分清真分页和假分页

大家都知道分页分为真分页和假分页,并且假分页是特别耗费性能的。我们在使用的过程中也是以真分页为主,但是在使用EF写分页语句的时候,稍有不慎,真分页便会成为假分页:

query.ToList().Skip((PageIndex - 1) * PageSize).Take(PageSize);

query.Skip((PageIndex - 1) * PageSize).Take(PageSize).ToList();

上面两句话乍一看差不多,并且都会实现我们分页的需求。但是这两句的执行过程,生成的sql语句大有不同。第一条语句的执行过程是:

a.先把数据全部都查询出来,放到内存中
b.转换成List
c.从List中进行分页操作,查询出结果。 这其实是假分页的效果。

而第二条语句就是真分页了,将参数传到数据库,生成分页sql语句,在数据库中查询出结果。


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

选择什么样的数据加载方式需要因时而异,如果选择不当很可能会影响系统性能,每一种数据加载方式都有它存在的意义,但目的只有一个,那就是以最少的代价获取到需要的数据。

关于EF几种加载方式的详细介绍:

EF学习和使用(五)Lazy Loading and Eager Loading

EF学习和使用(六)显式加载、按需加载


3.注意事务的简短性

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


4.NoTracking的使用

查询出来的实体,如果不需要删除和修改,请用NoTracking查询。

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

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


5.对于逻辑相对复杂的查询,要随时监控生成的Sql语句。

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


6.批量删除和修改

不知道你是否研究过EF的插入删除和修改操作,当你批量操作数据的时候,通过SQL Server Profiler可以明显看到产生了大量的Insert,Update语句,效率非常低;因为他插入一条数据,会对应生成一条Insert语句,当你的list中有10万条数据时,就会生成10万条插入语句!不过还好咱们有对策:Entity Framework Extendeds ,EF扩展类完美解决批量操作问题。篇幅原因,详见下回分解。



因为系统数据量暂时不大的原因,做了这些改变之后,性能提升并不是特别明显。但是积少成多,一点点的优化或进步我们都要争取。当系统数据量到了一定程度后,你会发现,这一点点的改变带给你的效果,将不只是一点点。


关于EF性能的研究,暂时涉及到了这些,后续将继续完善,敬请期待!