【问题标题】:cumulative SQL query execution time *MUCH* lower then EF ExecuteStoreCommands累积 SQL 查询执行时间 *MUCH* 低于 EF ExecuteStoreCommands
【发布时间】:2014-12-03 16:13:43
【问题描述】:

所以我一直在分析这个 MVC 应用程序,我注意到某些查询很慢,所以我自然而然地分析了我的应用程序和数据库。

这些是调查结果:

对于 29 个 SQL 命令,根据 MSSQL 分析器,所有 DB 调用的总和为 48ms。 这似乎是合理的。

编辑:这 29 个调用中的每一个都跟随着 exec sp_reset_connection 命令(不确定是否相关)。

这是奇怪的部分,应用程序分析是这样说的:

实体框架的

internal virtual DbDataReader ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior)

用了 578ms 来执行。或者让我进一步分解。

 private ObjectResult<T> GetResults(MergeOption? forMergeOption)
{
  this.QueryState.ObjectContext.AsyncMonitor.EnsureNotEntered();
  IDbExecutionStrategy executionStrategy = DbProviderServices.GetExecutionStrategy(this.QueryState.ObjectContext.Connection, this.QueryState.ObjectContext.MetadataWorkspace);
  if (executionStrategy.RetriesOnFailure && this.QueryState.EffectiveStreamingBehaviour)
    throw new InvalidOperationException(Strings.ExecutionStrategy_StreamingNotSupported((object) executionStrategy.GetType().Name));
  else
    return executionStrategy.Execute<ObjectResult<T>>((Func<ObjectResult<T>>) (() => this.QueryState.ObjectContext.ExecuteInTransaction<ObjectResult<T>>((Func<ObjectResult<T>>) (() => this.QueryState.GetExecutionPlan(forMergeOption).Execute<T>(this.QueryState.ObjectContext, this.QueryState.Parameters)), executionStrategy, false, !this.QueryState.EffectiveStreamingBehaviour)));
}

在 578 毫秒中需要 552 毫秒。

如果我进一步分解它。

public ObjectResult<T> Execute(MergeOption mergeOption)
    {
      EntityUtil.CheckArgumentMergeOption(mergeOption);
      return this.GetResults(new MergeOption?(mergeOption));
    }

397 毫秒

GetEnumerator 需要 155ms,该方法调用 Lazy 方法“CreateValue”等...

我会在这里停下来。

这些执行时间由 Jetbrains DotTrace 测量。

我确实意识到拥有 EF 本质上意味着“一些”开销。但这似乎太过分了。

EF 6.1.2, SQL Server 2012 标准版

我要求太多了吗?当期望“一些”开销而不是 12 倍开销时,我是否不合理?

或者我只是没有以正确的方式解决这个问题?

最好的问候, T.

【问题讨论】:

  • 嗯,你是在比较苹果和橙子。实体框架确实在查询数据库之外工作。它必须实例化对象,设置所有关系,初始化所有对象跟踪的东西。这些都不便宜,当涉及 29 个查询时,我认为 500 毫秒并不是那么糟糕。对于单个页面加载,这是相当多的查询。是的,任何 ORM 都会有开销。如果您的问题是 EF 的效率如何,那么您需要使用其他 ORM 选项进行分析,而不是针对直接 SQL。
  • 嗨,克里斯。我实际上并没有比较它,我只是对查询和执行它们所需的完整 EF 操作之间的差异幅度感到惊讶。就像我提到的那样,开销是预期的,因为“开销”用于创建应用程序对象等,就像你说的那样。我会将这些查询合并到更简单的视图或存储过程中,然后返回结果。
  • 实际上,您没有提到您的测试是如何构建的。 48ms 是否仅用于传输时间中的 SQL 因素?请记住,到数据库的往返需要一些时间,并且取决于所涉及的网络延迟,发送查询需要 100-200 毫秒,而接收结果需要另外 100-200 毫秒,这不会是异常的。如果是这种情况,那么您只看到 EF 大约 200 毫秒的处理时间,这仅比直接 SQL 增加了 4 倍。
  • 我认为网络或拓扑不是问题。这是在开发机器上的测试。一切都是本地的。
  • 好的,但这会使事情向相反的方向倾斜。本地开发分析几乎毫无用处,因为您的桌面类开发机器无法匹配实际的 Web 服务器,而且 IIS Express 是单线程的且未经过优化。真正的 IIS 将能够运行得更快,尤其是在服务器硬件上。开发分析仅用于确保在任何地方都没有巨大的异常瓶颈。否则,请将您的配置文件保存为您的生产服务器或其传真,例如 stage 或 QA。

标签: c# sql-server entity-framework asp.net-mvc-4 entity-framework-6


【解决方案1】:

默认情况下,Entity Framework 不仅仅执行查询,它还对数据进行序列化和反序列化,第一次运行任何 EF 命令时,它比后续调用花费更多时间,在测量之前进行蠕虫调用通话时间。

EF 所做的一些验证正在数据库上再次进行,例如数据完整性。

context.Configuration.AutoDetectChangesEnabled = false;

这将显着减少 EF 调用时间,但也会减少功能。

尝试挖掘更多,因为根据情况更改默认配置值可能会显着改变每次调用的时间。

最后是的,EF 对性能的影响很大,但在开发过程中消除了许多问题,而且服务器很便宜,程序员也很贵。

【讨论】:

  • AutodetectChangesEnabled 在此设置中已为假,我忘了提及。
  • 这只是可能对配置进行的更改的一个示例,最不推荐的一个也是做出重大更改的一个是 ValidateOnSaveEnabled,不建议禁用它,但它会更接近直接的 SQL 调用。对于简单的调用,最大的区别将是热身调用,因为 EF 在那里为序列化创建对象构造函数。
【解决方案2】:

也许我有点晚了,但请记住分析器也有它自己的开销,它取决于分析类型。对于 Sampling 它很小,对于 Timeline 稍大一点,然后是 Tracing,最重的是逐行。因此,要获得最准确的绝对函数执行时间,您应该使用采样。

但是,在 dotTrace 6.1 中,有一个选项可以在时间轴模式下分析客户端 SQL 交互,包括连接打开时间、执行和结果传输开销。所以你可以尝试一下,找出问题所在。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-24
    • 1970-01-01
    • 2010-09-15
    • 2011-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-08
    相关资源
    最近更新 更多