一. 开篇说明html
EF的性能问题一直以来常常被人所吐槽,究其缘由在于“复杂的操做在生成SQL阶段耗时长,且执行效率不高”,但并非没有办法解决,从EF自己举几个简单的优化例子:git
①:若是仅是查询数据,并不对数据进行增、删、改操做,查询数据的时候能够取消状态追踪。github
db.TestInfor.AsNoTracking().FirstOrDefault();
②:用什么查什么,好比一张表有100多个字段,本次业务只须要5个字段,必定是select这5个字段,而后toList,而不是所有查询,再toList()sql
③:利用EF调用原生SQL语句或者EF调用存储过程执行。 (目前为止,没有发现该方式存在什么问题,并且性能也很快,广大博友若是认为这种方式存在什么问题,能够留言给我普及扫盲一下)数据库
以上的几种方式,或许在必定程度上能解决一些问题,但面对大数据量的增、删、改,仍是心有力而力不足。缓存
1. 前面的章节异步
前面的章节提到了Z.EntityFramework.Extensions 插件解决EF性能问题,该插件确实很nb,性能很高,并且功能很全,可是呵呵,天上没有掉馅饼的好事,该插件是收费的,若是你公司不差钱,或者你是土豪,那么强烈推荐使用该插件,性能确实不错,而且你能够直接右上角 x,不须要看该篇文章了^_^。
async
但每每现实是残酷,穷人居多,这个时候就须要找免费的解决方案了,前面章节提到了 SqlBulkCopy 类(与EF没有半毛钱关系),它能够实现增长操做,不得不说,它在处理大数据量的增长的时候,确实很出色!!!。性能
那么删除和更新怎么办呢? 测试
答案是:能够借助 Z.EntityFrameWork.Plus.EF6 才解决。
2. 进入主题
Z.EntityFrameWork.Plus.EF6 和 Z.EntityFramework.Extensions 是同一公司的产物,该插件支持的功能不少,好比 删除、更新、缓存机制、过滤器等等,但惟独没有新增操做(都懂得,什么功能都有的话,他的兄弟 Z.EntityFramework.Extensions 怎么办?)。
本章节仅介绍删除和更新两个最经常使用的功能。
该插件的几点说明:
①:仅支持EF五、EF六、EF Core,注意不一样的版本对应该插件的后缀不一样,该章节使用的是EF 6.2,因此对应 Z.EntityFrameWork.Plus.EF6
②:官方号称:Improve EF Performance by 2000%
③:能够经过Nuget进行安装
④:文档地址 : http://entityframework-plus.net/batch-delete
GitHub地址: https://github.com/zzzprojects/EntityFramework-Plus
3. 数据库准备
二. 删除相关
1. Delete() 同步删除方法
2. DeleteAsync() 异步删除方法 <根据实际业务场景选择使用>
3. BatchSize:批次大小
Delete和DeleteAsync两个删除方法均可以设置该参数的值:x => x.BatchSize,该参数表示一次执行的条数,默认值为4000,好比你要删除4w条数据,默认值的话,就要删除10次,
适当的提升该值,会增长删除效率,但并不表明无限增大。
特别注意:下面测试使用的Delete方法是默认块级大小4000的状况下进行测试,后面把BatchSize直接改成8w,删除8w条数据在1.6s左右
4:BatchDelayInterval:批次执行的时间间隔
好比BatchSize=4000,BatchDelayInterval=1000,删除4w条数据,表示的意思是删除4000的时候等待1s,而后再删除。
PS:该参数不是很经常使用,适用于你既须要删除不少数据,并且在批处理之间的暂停间隔继续执行CRUD操做
5:Executing:执行删除命令以前,去执行一段命令文本
PS:根据实际场景选择使用。
下面进行性能测试:(1w条、 4w条、 8w条数据的删除操做)
(1). EF原生删除代码
1 /// <summary> 2 /// EF普通方法测试性能 3 /// </summary> 4 /// <param name="db"></param> 5 public static void DeleteCommon1(DbContext db) 6 { 7 Console.WriteLine("---------------------调用普通方法1删除--------------------------------"); 8 var list=db.Set<TestTwo>.Where(u=>u.id!="1").ToList();
9 Stopwatch watch = Stopwatch.StartNew();
10 foreach (var item in list) 11 { 12 db.Entry(item).State = EntityState.Deleted; 13 } 14 int count = db.SaveChanges(); 15 watch.Stop(); 16 Console.WriteLine($"{count}条数据耗时:{watch.ElapsedMilliseconds}"); 17 }
(2). EF调用SQL语句的代码
1 /// <summary> 2 /// EF调用SQL语句测试删除 3 /// </summary> 4 /// <param name="db"></param> 5 public static async void DeleteCommon2(DbContext db) 6 { 7 Stopwatch watch = Stopwatch.StartNew(); 8 string sql = "delete from TestTwo where id !='1' "; 9 int count = 0; 10 //加上await,表示在这一步上异步方法执行完 11 var response = await db.Database.ExecuteSqlCommandAsync(sql); 12 count = response; 13 Console.WriteLine("异步方法已经开始执行,请耐心等待"); 14 watch.Stop(); 15 Console.WriteLine($"{count}条数据耗时:{watch.ElapsedMilliseconds}"); 16 }
(3). 利用该插件扩展的代码
1 public static void DeletePlus(DbContext db) 2 { 3 Console.WriteLine("---------------------调用扩展方法删除--------------------------------"); 4 Stopwatch watch = Stopwatch.StartNew(); 5 int count = db.Set<TestTwo>().Where(u => u.id != "1").Delete(); 6 //设置块级大小(默认4000) 7 //int count = db.Set<TestTwo>().Where(u => u.id != "1").Delete(u => u.BatchSize = 80000); 8 watch.Stop(); 9 Console.WriteLine($"{count}条数据耗时:{watch.ElapsedMilliseconds}"); 10 }
最终的测试结论(下面的时间是取三次结果的平均值):
1w条数据 4w条数据 8w条数据
EF原生删除 76s 累哭了 累哭了
EF调SQL语句 1.152s 1.232s 1.558s
Z.Plus(默认块) 1.307s 1.982s 2.675s
最终结论: Z.EntityFrameWork.Plus.EF6的删除比EF原生要快的多! 但EF直接调用SQL语句貌似更快哈。
三. 更新相关
有了上面删除的基础,这里的更新操做就容易的多,更新的性能提高与删除相似,这里再也不单独测试了,下面简单粗暴,直接介绍用法。
1. Update() 同步更新方法
2. UpdateAsync() 异步更新方法
3. Executing:上述两个方法的一个参数,表示执行更新命令以前,去执行一段命令文本(根据实际状况选择使用)
直接上代码:
1 public static void UpdatePlus(DbContext db) 2 { 3 Console.WriteLine("---------------------调用扩展方法更新--------------------------------"); 4 Stopwatch watch = Stopwatch.StartNew(); 5 int count = db.Set<TestTwo>().Where(u => u.id != "1").Update(x => new TestTwo() 6 { 7 t21 = "0", 8 t22 = "1" 9 }); 10 watch.Stop(); 11 Console.WriteLine($"{count}条数据耗时:{watch.ElapsedMilliseconds}"); 12 }
综述:该插件的使用很是简单,在使用上,能够说没有任何难度可言,不少状况下,并非你不会解决,而是你缺乏一双善于发现的眼镜。
免费的大数据解决方案: SqlBulkCopy + Z.EntityFrameWork.Plus + EF调用SQL语句/存储过程 或许是一个不错的选择。
若是你对EF感兴趣,能够关注该章节:ORM系列之Entity FrameWork详解(持续更新)
!