园友莱布尼茨写了一篇《Entity Framework数据插入性能追踪》的文章,我感觉不错,至少他提出了问题,写了出来,引起了大家的讨论,这就是一个氛围。读完文章+评论,于是我自己也写了个简单的程序试了试。

先晒一下代码:

两个简单的类:

   1:      /// <summary>
   2:      /// 消费者
   3:      /// </summary>
   4:      public class Consumer
   5:      {
   6:          public int CId { get; set; }
   7:          public string CName { get; set; }
   8:          public List<Order> Orders { get; set; }
   9:      }
  10:   
  11:      /// <summary>
  12:      /// 订单
  13:      /// </summary>
  14:      public class Order
  15:      {
  16:          public int OrderNo { get; set; }
  17:          public DateTime OrderDate { get; set; }
  18:          public decimal TotalMoney { get; set; }
  19:          public int CId { get; set; }
  20:   
  21:          public Consumer Consumer { get; set; }
  22:      }

映射配置:

   1:      public class ConsumerConfiguration : EntityTypeConfiguration<Consumer>
   2:      {
   3:          public ConsumerConfiguration()
   4:          {
   5:              HasKey(t => t.CId).Property(t => t.CId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
   6:              Property(t => t.CName).IsRequired().HasMaxLength(50);
   7:          }
   8:      }
   9:   
  10:      public class OrderConfiguration : EntityTypeConfiguration<Order>
  11:      {
  12:          public OrderConfiguration()
  13:          {
  14:              HasKey(t => t.OrderNo);
  15:              HasRequired(t => t.Consumer).WithMany(t => t.Orders).HasForeignKey(t => t.CId);
  16:          }
  17:      }

Context:

   1:      public class TestContext : DbContext
   2:      {
   3:          public DbSet<Consumer> Consumers { get; set; }
   4:          public DbSet<Order> Orders { get; set; }
   5:   
   6:          protected override void OnModelCreating(DbModelBuilder modelBuilder)
   7:          {
   8:              modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
   9:   
  10:              modelBuilder.Configurations.Add(new ConsumerConfiguration());
  11:              modelBuilder.Configurations.Add(new OrderConfiguration());
  12:   
  13:              base.OnModelCreating(modelBuilder);
  14:          }
  15:      }

测试代码:

   1:          static void Main(string[] args)
   2:          {
   3:              using (var ctx = new TestContext())
   4:              {
   5:                  ctx.Consumers.Add(new Consumer()
   6:                  {
   7:                      CName = "张三"
   8:                  });
   9:                  ctx.SaveChanges();
  10:   
  11:                  Stopwatch sw = new Stopwatch();
  12:                  sw.Start();
  13:                  Console.WriteLine("订单开始:\n");
  14:   
  15:                  for (int outer = 0; outer < 20000; outer++)
  16:                  {
  17:                      ctx.Orders.Add(new Order()
  18:                            {
  19:                                OrderDate = DateTime.Now,
  20:                                TotalMoney = 100,
  21:                                CId = 1,
  22:                            });
  23:                  }
  24:                  ctx.SaveChanges();
  25:                  sw.Stop();
  26:                  Console.WriteLine(sw.Elapsed.Minutes + "分" + sw.Elapsed.Seconds + "秒" + sw.Elapsed.Milliseconds + "毫秒");
  27:              }
  28:          }

上面的代码是最平常的代码了,没有什么可解释的,将内容放到重点上。

运行以上代码的环境是VS2012+SQL SERVER 2008 R2,机器配置:4G,N年以前的CPU。

运行上面的代码非常的慢,正如莱布尼茨说的,在数据Add到上下文这个阶段比较耗时。出现这个问题的原因是:每次调用ctx.Orders.Add(order)之前,EF都会调用DetectChanges,在StackOverFlow上有解释,地址是:http://stackoverflow.com/questions/9439430/improving-performance-of-initializing-dbset-in-seed,另外在Programming Entity Framework DbContext这本书的60也有DetectChange的介绍。

解决上面速度慢的问题的办法就是设置

   1:  ctx.Configuration.AutoDetectChangesEnabled = false;

下面来看看禁用以后的执行速度:

另外一个解决办法就是使用DbSet<T>.AddRange方法,这个方法是在6.0 beta1中加入的。

   1:                  List<Order> orderList = new List<Order>();
   2:                  for (int outer = 0; outer < 20000; outer++)
   3:                  {
   4:                      orderList.Add(new Order()
   5:                             {
   6:                                 OrderDate = DateTime.Now,
   7:                                 TotalMoney = 100,
   8:                                 CId = 1
   9:                             });
  10:                  }
  11:                  ctx.Orders.AddRange(orderList);
  12:                  ctx.SaveChanges();

AddRange方法在System.Data.Entity 泛型DbSet类中,下图是我通过Reflector截的图

从上面两幅图中可以看到,Add和AddRange都是添加到_internalSet中,但是如果AutoDetectChangesEnabled设置为true的话,添加任何实体之前都会调用DetectChanges,注意看Remarks中的解释。

测试源码下载地址:http://www.ef-community.com/forum.php?mod=viewthread&tid=437&extra=page%3D1

"Entity Framework数据插入性能追踪"读后总结的更多相关文章

  1. Lazy<T>在Entity Framework中的性能优化实践

    Lazy<T>在Entity Framework中的性能优化实践(附源码) 2013-10-27 18:12 by JustRun, 328 阅读, 4 评论, 收藏, 编辑 在使用EF的 ...

  2. 大数据应用之HBase数据插入性能优化实测教程

    引言: 大家在使用HBase的过程中,总是面临性能优化的问题,本文从HBase客户端参数设置的角度,研究HBase客户端数据批量插入性能优化的问题.事实胜于雄辩,数据比理论更有说服力,基于此,作者设计 ...

  3. Entity Framework 数据并发访问错误原因分析与系统架构优化

    博客地址 http://blog.csdn.net/foxdave 本文主要记录近两天针对项目发生的数据访问问题的分析研究过程与系统架构优化,我喜欢说通俗的白话,高手轻拍 1. 发现问题 系统新模块上 ...

  4. 关于Entity Framework采用DB First模式创建后的实体批量修改相关属性技巧

    Entity Framework采用DB First模式创建实体是比较容易与方便的,修改已创建的实体在个数不多的情况下也是没问题的,但如果已创建的实体比较多,比如10个实体以上,涉及修改的地方比较多的 ...

  5. .NET基础篇——Entity Framework 数据转换层通用类

    在实现基础的三层开发的时候,大家时常会在数据层对每个实体进行CRUD的操作,其中存在相当多的重复代码.为了减少重复代码的出现,通常都会定义一个共用类,实现相似的操作,下面为大家介绍一下Entity F ...

  6. asp.net mvc常用的数据注解和验证以及entity framework数据映射

    终于有时间整理一下asp.net mvc 和 entity framework 方面的素材了. 闲话少说,步入正题: 下面是model层的管理员信息表,也是大伙比较常用到的,看看下面的代码大伙应该不会 ...

  7. .NET批量大数据插入性能分析及比较

    数据插入使用了以下几种方式 1. 逐条数据插入2. 拼接sql语句批量插入3. 拼接sql语句并使用Transaction4. 拼接sql语句并使用SqlTransaction5. 使用DataAda ...

  8. 大数据应用之HBase数据插入性能优化之多线程并行插入测试案例

    一.引言: 上篇文章提起关于HBase插入性能优化设计到的五个参数,从参数配置的角度给大家提供了一个性能测试环境的实验代码.根据网友的反馈,基于单线程的模式实现的数据插入毕竟有限.通过个人实测,在我的 ...

  9. Lazy<T>在Entity Framework中的性能优化实践(附源码)

    在使用EF的过程中,导航属性的lazy load机制,能够减少对数据库的不必要的访问.只有当你使用到导航属性的时候,才会访问数据库.但是这个只是对于单个实体而言,而不适用于显示列表数据的情况. 这篇文 ...

随机推荐

  1. 巨蟒python全栈开发-第5天 字典&集合

    今日大纲: 1.什么是字典 字典是以key:value的形式来保存数据,用{}表示. 存储的是key:value 2.字典的增删改查(重点) (1) 添加 dic[新key] = 值 setdefau ...

  2. 常见面试题整理--Python概念篇

    希望此文可以长期更新并作为一篇Python的面试宝典.每一道题目都附有详细解答,以及更加详细的回答链接.此篇是概念篇,下一篇会更新面试题代码篇. (一).这两个参数是什么意思:*args,**kwar ...

  3. Django页面重定向

    重定向分为永久性重定向和暂时性重定向,在页面上体现的操作就是浏览器会从一个页面自动跳转到另外一个页面.比如用户访问了一个需要权限的页面,但是该用户当前并没有登录,因此我们应该给他重定向到登录页面. 永 ...

  4. “技术产品”面向市场的表达方法思辨——BY Me

    “技术产品”面向市场的表达方法思辨 首先,我们来看看“技术产品”在面向市场去表达的时候,怎么表述是容易被市场接受和理解的,“目标受众是谁?”.“市场切入点是什么?”,做到有的放矢,打动目标受众.切中其 ...

  5. node.js---sails项目开发(3)

    1.为新建的sails数据库新建一个用户,首先连接数据库 mongo localhost:27017 (1)显示所有数据库   (2)切换数据库 show dbs use sails 新建一个用户 账 ...

  6. (转)VLC播放RTP打包发送的.264文件

    VLC播放RTP打包发送的.264文件 1,要有一个发送RTP包的264文件的服务器; 具体代码如下: rtp.h #include <WinSock2.h> #pragma commen ...

  7. Jupyter Notebook修改目标文件

    默认的路径 如果没有修改配置文件,那么一般就在用户目录下面: 下面各处默认起始目标地址,以防有一天想改回来 I:\shujufenxi\python.exe I:\shujufenxi\cwp.py ...

  8. Loadrunner场景设计篇——负载生成器

    1  简介 当执行一个场景时,Controller把场景中的每个用户配到负载生成器(Load generator). 所谓的负载生成器(Load Generator)就是执行Vuser脚本,运行Vus ...

  9. js刷新页面 location.reload()

    在javascript编程中,多使用location.reload实现页面刷新. 例子: 代码示例: window.location.href=window.location.href; window ...

  10. 【Head First Servlets and JSP】笔记24:include指令与include动作 & param动作 & foward动作

    include指令与include动作 1.样例代码 <%@ page contentType="text/html;charset=UTF-8" language=&quo ...