EF性能优化

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


1、分清真分页和假分页

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

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

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

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

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


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

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


3.注意事务的简短性

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


4.NoTracking的使用

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

    using (var context = new MyDbContext())
    { 
         var people = context.People.Where(p => p.PersonID > 100).AsNoTracking().ToList(); } 
  • 1
  • 2
  • 3
  • 4
  • 5

有时我们的实体只需要显示,无需更新,所以为了提高性能,我们不需要实体被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扩展类完美解决批量操作问题。



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

优化方法总结

1.连接保持畅通

意思是不要在需要的时候连接了不需要的时候断开,需要了又去连接(特殊情况除外),目的在于减少对数据库的操作。

2.关闭EF的一些配置

EF使用时,会在Config中配置,对于使用CRUD功能,有一些是用不到的,可以关闭,关闭后的测试效果加快几秒,略微提升。 
这里写图片描述

3.存入List

EF支持AddRange,如果需要存5条数据,将这5条数据放入list一次存入,要比一条一条的存大大的快。

4.查找数据用Linq or Lamba

遇到这样的情况,你需要从数据库中取某一条特定的数据,然后处理这条数据后存入另一个表,用foreach是吧,太慢了,换成Linq,上面草图中有个备注,再换成lamba试试。

5.数据放入内存

如果要从一个表中多次找数据来使用,那不如第一步先将这个表中所有数据或者需要的那部分特征数据都先放入内存中,从内存中读取的速度,大大的快于操作数据库,而这目的,也就是减少操作数据库的次数,耗性能。

6.使用BulkInsert

使用插件Extended,使用其中的BulkSaveChanges代替EF原生态的SaveChanges来保存数据,附截图来引用一段话:

这里写图片描述

然后我亲测结果如图: 
这里写图片描述 
1000条数据,BulkSaveChanges花费1s,SaveChanges花费27s……

插件名: 
这里写图片描述

对于该插件的一些使用方法,我也附上网址: 
http://www.zzzprojects.com/products/dotnet-development/bulk-operations/

7.使用SQL语句

如果你对速度还不满意,可以CRUD,直接使用SQL语句来操作。 
可以参考: 
http://my.oschina.net/Yamazaki/blog/185621

8.多表只需存一张

遇到这样的情况,P、T两张表,关系是1—–(0,1)的关系,你可能会先存入P表的数据,然后foreach P表的数据,找到对应的给T表的导航属性赋值,然后存入这条数据到T表,这个问题很严重也可笑,但是我身上缺犯了,只需要存 必须存导航数据(T表数据),有关联的表数据自然存入了(P表)

结尾

上述我总结的方法中,没有使用SQL语句,原先花费1小时20分钟的事,现在花费70s,竟然真的做到了。

猜你喜欢

转载自www.cnblogs.com/shiyh/p/8979508.html
EF