【问题标题】:Entity Framework 4 : Bad performance with SQL Server 2008实体框架 4:SQL Server 2008 性能不佳
【发布时间】:2010-10-08 13:27:25
【问题描述】:

我正在开发一个基于实体框架的软件来处理 MS SQL Server 2008 数据库中的数据。

[问题 1]

我刚刚尝试将一些小数据(大约 2 Mb)从我的程序插入到数据库:性能非常糟糕!插入这些数据需要超过 1 分钟

我尝试生成预编译的视图,我得到了相同的结果:-(

我的所有代码都使用业务层(使用 T4 模板从 .edmx 文件自动生成)来管理服务层中的数据。在对象的关系中导航非常实用。

如何使用 Entity Framework 提高这些插入的性能?

[麻烦 2]

另外,在使用 SaveChanges() 方法将数据插入数据库之前,我使用 AddObject() 方法填充我的对象上下文。我使用 AddObject() 将大约 100 000 个小对象(大约 2 Mb)添加到我的对象上下文中:这需要很长时间(超过 10 分钟)!

如何减少这个时间?

更新

我的程序必须在 2-3 分钟内保存超过 50 Mb 的数据库?你认为 EF 可以吗?

【问题讨论】:

  • 实体框架是初始易用性和性能之间的权衡。如果您对性能感兴趣,请远离实体框架
  • @Andomar,这非常无用。这不是正常的表现。移除 EF 可能无法修复它,无论如何都会像斩首治疗痤疮一样。 Patrice 需要分析应用程序以发现问题,而不是随意指责工具。
  • @Craig Stuntz:所以,在您看来,建议某人配置 EF 更有帮助?呵呵
  • @Andomar:Patrice 分析正在开发的应用程序绝对比随机重写基础设施更有用。基于偏见的建筑很少是成功的策略。
  • @Craig Stuntz:我假设它是一个新的应用程序,还不能工作,并且存在无法克服的性能问题。正是您对 EF 应用程序的期望

标签: c# performance entity-framework sql-server-2008


【解决方案1】:

您可以使用Entity Framework Profiler 来检查正在生成的SQL。该工具有 30 天的免费试用期。它还声称它可以“分析和检测使用实体框架时的常见陷阱”。

还有this关于EF调优的文章

编辑

根据您的编辑,EF 不是可行的方法。您需要进行批量插入才能快速获取数据。查看this 链接,我帮助某人将加载时间从 10 小时缩短到 6 分钟。

【讨论】:

  • @Shiraz:我可以将批量插入与 EF 混合使用吗?
  • @Patrice,看起来不可能,请参阅:stackoverflow.com/questions/1609153/…
  • @Shiraz,在 EF 4 中,您可以通过ObjectContext.ExecuteStoreCommand.执行“本机”SQL 服务器语句@这可能是进行批量加载的最佳方式。但我仍然想知道来源。如果是,例如 CSV 文件,SSIS 包可能是最合适的。
  • Patrice,在我看来,您的问题不仅仅是一个性能点。您需要进行架构审查。我认为这不仅仅是一个 SO 问题所能做的。一个起点可能是这篇文章cacm.acm.org/magazines/2010/6/92486-managing-scientific-data/… 虽然它处理的是更大的数据规模,但它讨论了所涉及的问题。
  • @Craig - 这也是我的猜测(架构问题)。我想知道数据库的结构。我使用 EF 处理大量数据,从未遇到过此类问题。
【解决方案2】:

这里有几种可能性。

  1. 数据库硬件可能无法胜任处理 100,000 次插入的任务。涉及多少张表?是否有辅助考虑因素,例如触发的触发器?数据库内存是否受限?

  2. Web 服务器硬件可能无法胜任处理这么多负载的任务。数据来自哪里?传输到网络服务器需要多长时间? Web 服务器实际向数据库服务器发送多少次插入/秒?

总而言之,您必须进行剖析才能准确找出瓶颈所在。根据您目前提供的信息,它可能在任何地方。

您需要在 Web 服务器上运行探查器,并且需要在数据库服务器上使用 SQL Profiler。此外,您应该在加载数据时监控两台机器的 CPU、内存和网络使用情况图表。

获得所有数据后,您应该能够查明问题出在哪里。

更新
附带说明一下,EF 必须创建至少 100,000 个对象来保存您正在上传的数据(每条记录一个)。这有它自己的开销,这就是为什么 ORM 通常不是大规模插入/更新数据的好主意。

更新 2
如果您在完全相同的台式机上同时运行客户端和数据库服务器,那么您可能会遇到硬件问题。希望您拥有至少 4 GB 内存的多核系统。您系统上的所有内容都将争夺资源:Visual Studio、SQL Server、应用程序本身,以及您碰巧正在运行的任何其他内容。 Studio 和 SQL Server 占用大量内存和 CPU。 (仅供参考 - SQL 服务器不会向任务管理器报告所有内容)

重点是,除非您使用嵌入式 sql 服务器部署应用程序,否则这不会接近真实世界的测试,并且您看到或缺乏的性能与真实世界的场景无关。

【讨论】:

  • 1.我说的是仅 1 个表中的 2 Mb 数据(按行 20 个字节)。没有触发器。如何查看数据库内存是否受限?这点可以解释非常慢的 AddObject() 吗? 2. SQL Server 位于 localhost 3. 我的程序不是 Web 应用程序。它是 C# 中的一个重度客户端。
  • @Patrice:拉起任务管理器并转到性能选项卡。执行上传时,会发生什么?是否有可用内存或磁盘抖动?此外,如果您在调试模式下运行它,请不要。在发布模式下运行它。
  • @Patrice:然后拉出 SQL Profiler 并观察遇到的事务,以了解它如何影响系统的其余部分。
  • @Chris:可以插入,但我怎样才能减少 AddObject 时间?
  • @Patrice:优化 EF 有点超出我的能力。因为这样的事情,我不使用它。我解决这个问题的方法是使用一个存储过程,它接受一个包含我想要插入的所有数据的表值参数,或者使用某种类型的批量加载功能。
【解决方案3】:

EF(以及 LINQ2SQL)对每条记录进行一次更新/插入。这通常会导致批量插入/更新的性能低于可接受的水平。 解决方法是创建存储过程,它将为您完成这些任务。在大多数情况下,这是一个可接受的解决方案,当您对少量对象类型执行这些操作时,在这种情况下使用 EF 并手动编写这些 SP,然后将它们添加到 EDMX 仍然是可行的。 你可以google一下在EF中使用存储过程。

【讨论】:

    【解决方案4】:

    可能不是实体框架,而是您的数据库架构是罪魁祸首,例如错误的聚集索引或过多的索引。

    您可以使用ObjectQuery.ToTraceString 属性查看Entity Framework 生成的SQL。

    如果 Entity Framework 生成的 SQL 不能满足您的需求,您可以使用自己的存储过程进行创建、更新和删除操作。

    【讨论】:

    • 事实上,使用方法.AddObject() 在上下文中添加新对象的过程似乎也很长:-(.
    • 恕我直言,即使是最可怕的模式设计也无法解释几个插入需要一分钟才能完成
    【解决方案5】:

    您可以使用 SQL Server Profiler 分析查询,然后使用数据库引擎优化顾问来确定要添加的更好的统计信息和索引。

    【讨论】:

    • @Andomar,你不知道问题出在哪里。如果在AFTER INSERT 触发器中查询很慢,那么添加索引可能确实会使插入速度更快。 “分析它并找到问题”是这里唯一正确的答案。帕特里斯的问题中没有足够的信息可以说更多。
    【解决方案6】:

    在最初的问题中,我的印象是一次创建了大约 100,000 个对象,并且只调用了一次 SaveChanges。这种只有一次 SaveChanges 调用的大型工作单元对于实体框架来说几乎总是一个非常糟糕的性能想法。我会尝试将事情分成一系列批次,大约有 100 个对象,并在每个批次之间调用 SaveChanges。事实上,我什至会处理上下文并在批次之间创建一个新的上下文,因为否则您最终会立即在状态管理器中使用所有这些对象,这会增加开销。您可能需要尝试不同的批次大小才能找到最佳数量。

    另外,您可能需要考虑您使用的是什么类型的实体。如果您使用 poco 实体,那么当您使用实现 IEntityWithChangeTracking 的类(或从实现该接口的 EntityObject 继承)时,检测不存在的更改会产生一些开销。

    • 丹尼

    【讨论】:

      【解决方案7】:

      正如其他人或多或少指出的那样,Entity Framework 的工作原理是为每个对象发送一条语句,然后再发送一条附加语句来取回数据库分配的 ID 值。

      在许多对象上运行时,这非常慢,尤其是当到数据库服务器的往返时间超过 1 毫秒时。

      为了在将许多对象存储到数据库时提高性能,请使用 SqlBulkCopy 类而不是 Entity Framework。

      您可以在本文中找到 Entity Framework 和 SqlBulkCopy 的完整比较:How to Bulk Insert Complex Objects into SQL Server Database

      【讨论】:

        【解决方案8】:

        我当前的项目遇到了类似的问题。我附加到 SQL Profiler 并开始了我的流程。每次保存更改时,实体框架似乎都会为每个 INSERT 或 UPDATE 启动一个 SQL 事务。

        我不确定这是否与问题有关,但我会运行 SQL Profiler 并检查结果。我还会在你的 SQL 机器上监控你的磁盘使用情况(读取和写入)(如果可能的话),看看是否有任何危险信号。

        【讨论】:

        • 插入始终是事务的一部分。如果 Entity Framework 没有为每个插入启动一个事务,SQL Server 将自动启动一个。在默认模式下,SQL Server 启动的事务将在插入后立即提交。这称为隐式事务。
        • 啊,好吧。谢谢提供信息。那么如果有大量的 INSERT 或 UPDATE 操作发生,这和性能有关系吗? SQL 事务是否会显着增加性能开销?
        • SQL 事务是必需的,所以从技术上讲,它们不会增加开销,它们只是插入的一部分。对于大型导入,请查看批量插入。
        • 我对 EF 了解不多,但您不应该在开始大型插入或更新操作之前显式启动事务吗?这将节省 SQL Server 为每一行创建一个新事务,这将大大加快您的操作。
        • @Pradeep - 这就是我的目标。如果有一个大型数据集(假设 >= 1000 条记录),如果每一行都运行自己的事务,是否会影响性能?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-04-06
        • 2017-12-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多