第二十三节: EF性能篇(三)之基于开源组件 Z.EntityFrameWork.Plus.EF6解决EF性能问题

一. 开篇说明

  EF的性能问题一直以来经常被人所吐槽,究其原因在于“复杂的操作在生成SQL阶段耗时长,且执行效率不高”,但并不是没有办法解决,从EF本身举几个简单的优化例子:

  ①:如果仅是查询数据,并不对数据进行增、删、改操作,查询数据的时候可以取消状态追踪。

     db.TestInfor.AsNoTracking().FirstOrDefault();

  ②:用什么查什么,比如一张表有100多个字段,本次业务只需要5个字段,一定是select这5个字段,然后toList,而不是全部查询,再toList()

  ③:利用EF调用原生SQL语句或者EF调用存储过程执行。 (目前为止,没有发现该方式存在什么问题,而且性能也很快,广大博友如果认为这种方式存在什么问题,可以留言给我普及扫盲一下

  以上的几种方式,或许在一定程度上能解决一些问题,但面对大数据量的增、删、改,还是心有力而力不足。

1. 前面的章节

  前面的章节提到了Z.EntityFramework.Extensions插件解决EF性能问题,该插件确实很nb,性能很高,而且功能很全,但是呵呵,天上没有掉馅饼的好事,该插件是收费的,如果你公司不差钱,或者你是土豪,那么强烈推荐使用该插件,性能确实不错,并且你可以直接右上角 x,不需要看该篇文章了^_^。

  但往往现实是残酷,穷人居多,这个时候就需要找免费的解决方案了,前面章节提到了 SqlBulkCopy 类(与EF没有半毛钱关系),它可以实现增加更新操作,不得不说,它在处理大数据量的增加的时候,确实很出色,但他的更新操作,是个残废!!!

  那么删除和更新怎么办呢?

  答案是:可以借助 Z.EntityFrameWork.Plus.EF6 才解决。

2. 进入主题

  Z.EntityFrameWork.Plus.EF6  和 Z.EntityFramework.Extensions 是同一公司的产物,该插件支持的功能很多,比如 删除、更新、缓存机制、过滤器等等,但唯独没有新增操作(都懂得,什么功能都有的话,他的兄弟 Z.EntityFramework.Extensions 怎么办?)。 

  本章节仅介绍删除和更新两个最常用的功能。 

该插件的几点说明:

  ①:仅支持EF5、EF6、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             Stopwatch watch = Stopwatch.StartNew();
 9             var list = db.Set<TestTwo>().Where(u => u.id != "1").ToList();
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详解(持续更新)

!

  • 作       者 : Yaopengfei(姚鹏飞)
  • 博客地址 : http://www.cnblogs.com/yaopengfei/
  • 声     明1 : 本人才疏学浅,用郭德纲的话说“我是一个小学生”,如有错误,欢迎讨论,请勿谩骂^_^。
  • 声     明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,如需代码请留下你的评论,加我QQ:604649488 (备注:评论的博客名)

原文地址:https://www.cnblogs.com/yaopengfei/p/9226328.html

时间: 2024-08-06 18:46:29

第二十三节: EF性能篇(三)之基于开源组件 Z.EntityFrameWork.Plus.EF6解决EF性能问题的相关文章

(转)第二十三节 inotify事件监控工具

第二十三节 inotify事件监控工具 标签(空格分隔): Linux实战教学笔记-陈思齐 原文:http://www.cnblogs.com/chensiqiqi/p/6542268.html 第1章,NFS存储服务器与backup备份服务器的搭建. 详细细节知识与搭建请关注: http://www.cnblogs.com/chensiqiqi/p/6514315.html Rsync数据同步工具 http://www.cnblogs.com/chensiqiqi/p/6530859.html

centos mysql 优化 第二十三节课

centos mysql  优化  第二十三节课 f

第二十三节(String,StringBuffer,基础类型对应的 8 个包装类,日期相关类、 Random 数字 ,Enum枚举)下

/* java.lang.String 是字符串类型 注意:只要采用双引号赋值字符串,那么在编译期将会放到方法区中的字符串的常量池里, 如果是运行时对字符串.加或相减会放到堆中(放之前会先验证方法区中是否含有 相同的字符串常量,如果存在,把地址返回,如果不存在,先将字符串常量放到池中,然 后再返回该对象的地址 */ public class StringTest01{ // java的入口 public static void main(String[] args){ // 创建一个“abc”字

centos mysql 实战 第二十三节课

f

第二百一十三节,jQuery EasyUI,NumberBox(数值输入框)组件

jQuery EasyUI,NumberBox(数值输入框)组件 功能:只能输入数值,和各种数值的计算 学习要点: 1.加载方式 2.属性列表 3.事件列表 4.方法列表 本节课重点了解 EasyUI 中 NumberBox(数值输入框)组件的使用方法,这个组件依赖 于 ValidateBox(验证框)组件. 一.加载方式 class 加载方式 <input type="text" class="easyui-numberbox" value="10

第二十三节(表单验证)

<title>form表单验证 </title> <style> /*验证css开始*/ /* common css ============================================== */ body{margin:0 auto;text-align:center;font:12px/1.5 arial;color:#242424;background:#212222;} div{text-align:left;} :focus{outline

[ExtJS5学习笔记]第二十三节 Extjs5中表格gridpanel的列格式设置

本文地址:http://blog.csdn.net/sushengmiyan/article/details/39665979 官方文档:http://docs.sencha.com/extjs/5.0/apidocs/#!/api/Ext.grid.column.Date 本文作者:sushengmiyan ----------------------------------------------------------------------------------------------

第二十三节,不同数据类型在内存中的存址方式

不同数据类型在内存中的存址方式 字符串str,一次性创建,不能被修改,只要有修改字符串,就是在重新创建新的字符串Python底层是c语言写的,c语言没有字符串的说法,字符串是字符数组,所以在内存址是字符数组的方式

php第二十三节课

XML XML:页面之间传递数据,跨平台传递 HTML:超文本标记语言,核心标签 XML特点:1.标签名可以自己定义2.有且只有一个根3.大小写敏感4.标签必须完整 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http