【问题标题】:Why is EF4 Code First so slow when storing objects?为什么存储对象时 EF4 Code First 这么慢?
【发布时间】:2011-03-21 13:39:39
【问题描述】:

我目前正在对我的 Web 应用程序使用 db4o 存储进行一些研究。我很高兴 db4o 的工作如此简单。因此,当我读到 Code First 方法时,我有点喜欢,因为使用 EF4 Code First 的方式与使用 db4o 非常相似:创建您的域对象 (POCO),将它们扔给 db4o,然后再也不回头。

但是当我进行性能比较时,EF 4 的速度非常慢。我不知道为什么。

我使用以下实体:



public class Recipe { private List _RecipePreparations; public int ID { get; set; } public String Name { get; set; } public String Description { get; set; } public List Tags { get; set; } public ICollection Preparations { get { return _RecipePreparations.AsReadOnly(); } }

    public void AddPreparation(RecipePreparation preparation) 
    {
        this._RecipePreparations.Add(preparation);
    }
}

public class RecipePreparation { public String Name { get; set; } public String Description { get; set; } public int Rating { get; set; } public List Steps { get; set; } public List Tags { get; set; } public int ID { get; set; } }

为了测试性能,我新建了一个配方,并添加了 50.000 个配方准备。然后我像这样将对象存储在 db4o 中:

IObjectContainer db = Db4oEmbedded.OpenFile(Db4oEmbedded.NewConfiguration(), @"RecipeDB.db4o");
db.Store(recipe1);
db.Close();

这大约需要 13.000(毫秒)

我将使用 EF4 的内容存储在 SQL Server 2008(Express,本地)中,如下所示:

cookRecipes.Recipes.Add(recipe1);
cookRecipes.SaveChanges();

这需要 200.000 (ms)

现在 db4o 到底如何比 EF4/SQL 快 15(!!!) 倍?我是否缺少 EF4 的秘密加速按钮?我什至认为 db4o 可以做得更快?由于我没有初始化数据库文件,我只是让它动态增长。

【问题讨论】:

  • 我的猜测是,执行许多单个插入语句的开销是差异的最大部分。有没有办法指示 EF4 组合插入语句以减少开销?
  • @Lasse:是的,有。 EF 实现了开箱即用的工作单元模式 - 请参阅我的答案。
  • 我已经使用 Visual Studio 进行了一些分析。并且 cookRecipes.Recipes.Add(recipe1) 需要大约 65% 的总时间来存储,而 SaveChanges 大约需要 35% (duh ... ;))。
  • 不确定它有多重要,但您使用的是什么 CTP 版本的纯代码?
  • CTP 4 从这里下载:microsoft.com/downloads/…

标签: c# entity-framework db4o


【解决方案1】:

也许您可以在添加新对象时禁用更改跟踪,这确实会提高性能。

context.Configuration.AutoDetectChangesEnabled = false;

另请参阅:http://coding.abel.nu/2012/03/ef-code-first-change-tracking/

【讨论】:

    【解决方案2】:

    只是补充一下其他答案:db4o 通常在进程内运行,而 EF 抽象出进程外 (SQL) 数据库。但是,db4o 本质上是单线程的。因此,虽然对于这个带有一个请求的示例可能更快,但 SQL 将比默认的 db4o 数据库设置更好地处理并发(多个查询、多个用户)。

    【讨论】:

      【解决方案3】:

      EF 擅长很多事情,但批量加载不是其中之一。如果您想要高性能的批量加载,直接通过数据库服务器执行此操作将比 any ORM 更快。如果您的应用唯一的性能限制是批量加载,那么您可能不应该使用 EF。

      【讨论】:

      • 那我对EF的使用有疑问了。当您的应用程序依赖于非常复杂的模型(域对象)时,我更喜欢 oo 数据库(如 db4o)。但是当数据主要是表格时,您将使用传统的关系数据库,以及可选的 OR/M,如 EF。但是正如您所说,当您进行大量负载/插入/更新时,EF 会失败。所以我害怕的是真的。 EF4 仅在执行非常轻量的数据库操作时是一种选择,并且您只能使用关系数据库。
      • 再一次,不仅仅是 EF,any ORM 将比数据库服务器的批量加载功能慢。 EF 可能比支持批量插入的 ORM 慢,但即使是那些也不会像 DB 服务器专用批量加载功能上使用的流 API 一样快。对于大多数应用程序来说,批量加载是一种极端情况,但如果它是你的生计,那么你最好使用 SSIS 之类的东西而不是 ORM。
      • 我同意大多数 OR/M 会比批量加载慢。但我不同意 OR/M 也不能利用数据库的批量加载功能。代码很容易生成。但我认为 EF4 Code First 出了点问题。由于仅将 Recipe 实体添加到 dbContext 需要很长时间(130 秒)。在数据库中存储 (dbContext.Recipes.SaveChanges) 也不是速度恶魔,50.001 行需要 70 秒。转换为 50.000/70 = 714 行/秒。
      • 我没有说他们不能使用批量加载功能。我说他们通常不会。也就是说,如果添加 1 个实体需要 130 秒,那么你的情况就完全不同了。那不是正常的表现。也许您正在创建数据库?代码优先可以隐式地做到这一点。
      • 嗯,这就是我以前做的。但现在它应该连接到现有数据库。但是我必须检查它是否不仅仅是检查所有实体是否与数据库中的表具有相同的结构。
      【解决方案4】:

      你有没有在循环中调用SaveChanges() inside?难怪它很慢!尝试这样做:

      foreach(var recipe in The500000Recipes)
      {
          cookRecipes.Recipes.Add(recipe);
      }
      cookRecipes.SaveChanges();
      

      EF 希望您进行所有您想要的更改,然后调用SaveChanges一次。这样,它可以优化数据库通信和 sql 以执行打开状态和保存状态之间的更改,忽略您已撤消的所有更改。 (例如,添加 50 000 条记录,然后删除其中的一半,然后点击 SaveChanges 只会将 25 000 条记录添加到数据库中。永远。)

      【讨论】:

      • 循环发生在任何数据存储在 db4o 或 EF4/SQL 中之前。所以我首先新建了Recipe,然后在循环中添加RecipePreparations。所以现在我有一个食谱,附有 50.000 RecipePreparation。然后我将它存储在 db4o 或 EF4/SQL 中。所以 db4o 中有一个 db.store(recipe1),EF4 中有一个 cookRecipes.Recipes.Add(recipe1);cookRecipes.SaveChanges()。
      • DB4O 正在保存到本地机器上的文件中,对吗? EF4 必须在本地打开数据库连接。连接通常会保持打开状态,因此它是每次启动一次的成本。尝试在插入的计时循环之前添加一行以获取数据库中的第一项,以使该连接时间超出等式。
      猜你喜欢
      • 1970-01-01
      • 2013-09-19
      • 2016-08-09
      • 2010-10-05
      • 1970-01-01
      • 1970-01-01
      • 2013-05-25
      • 2012-02-13
      • 2021-09-03
      相关资源
      最近更新 更多