【问题标题】:Entity framework performance slow实体框架性能慢
【发布时间】:2016-11-10 11:03:24
【问题描述】:

我们正在使用 EF 6.0、.NET 4.5 并使用代码优先方法,我们的数据库有大约 170 个实体(表),主表包含大约 150,000 条记录 第一次加载实体框架大约需要 25 秒。 我正在尝试改进这个时间,因为这太慢了,并且随着记录数量的增加,它变得更慢。 我尝试生成原生图像,尝试使用预生成的交互式视图,但我无法取得任何重大改进。

谁能帮我解决这个问题?

谢谢。

【问题讨论】:

  • 确保启用延迟加载
  • 你真的使用代码中的所有 170 个表吗?
  • 您能否展示一个需要很长时间才能完成的示例查询?
  • @asdf_enel_hak 是的延迟加载已启用
  • @ErikEJ 是的,我们需要所有这些,这是一个不断增长的数据模型。

标签: c# performance entity-framework entity-framework-6


【解决方案1】:

您可以考虑Entity Framework Pre-Generated Mapping Views。您可以使用EF Power Tools来创建预生成视图。

使用预先生成的视图可以降低模型生成视图的成本 加载(运行时)到编译时。虽然这改善了启动 运行时的性能,你还是会体验到视图的痛苦 一代,而你正在发展。还有几个额外的 有助于降低视图生成成本的技巧,无论是在 编译时间和运行时间。

您可以参考这篇文章以了解更多信息:Entity Framework Pre-Generated Mapping Views

您可以使用实体框架中的缓存来提高应用的性能。

缓存有 3 种类型。

1.对象缓存 – 内置于 ObjectContext 中的 ObjectStateManager 实例在内存中跟踪已被 使用该实例检索。这也称为一级 缓存。

2。查询计划缓存 - 重用生成的存储命令,当 查询多次执行。

3.元数据缓存 - 跨不同共享模型的元数据 连接到同一模型。

您可以参考这篇文章了解更多信息:Performance Considerations for EF 6

【讨论】:

  • 我尝试过使用预生成的视图,但没有帮助。将尝试缓存选项。
【解决方案2】:

我最近有一个简单的查询,它在 SSMS 中运行得非常快,但在我的 C# 程序中使用实体框架运行时间太长了。

此页面在解决一般 EF 性能问题时非常有用:

https://www.simple-talk.com/dotnet/net-tools/entity-framework-performance-and-what-you-can-do-about-it/

..但在这种情况下,没有任何帮助。所以最后,我做到了:

        List<UpcPrintingProductModel> products = new List<UpcPrintingProductModel>();
        var sql = "select top 75 number, desc1, upccode "
                + "from MailOrderManager..STOCK s "
                + "where s.number like @puid + '%' "
        ;
        var connstring = ConfigurationManager.ConnectionStrings["MailOrderManagerContext"].ToString();
        using (var connection = new SqlConnection(connstring))
        using (var command = new SqlCommand(sql, connection)) {
            connection.Open();
            command.Parameters.AddWithValue("@puid", productNumber);
            using (SqlDataReader reader = command.ExecuteReader()) {
                while (reader.Read()) {
                    var product = new UpcPrintingProductModel() {
                        ProductNumber = Convert.ToString(reader["number"]),
                        Description = Convert.ToString(reader["desc1"]),
                        Upc = Convert.ToString(reader["upccode"])
                    };
                    products.Add(product);
                }
            }
        }

(对于这个特定的查询,我完全绕过了 EF,并使用了旧的备用:System.Data.SqlClient。)

你可以厌恶地皱起鼻子;我当然做到了——但实际上并没有花那么长时间来编写,而且几乎可以立即执行。

【讨论】:

  • “皱我的鼻子”?!这是超级聪明的。 +1 将 EF 用于主流,并在有意义的情况下区分例外情况。这是约定优于配置的绝佳示例。
【解决方案3】:

您还可以在应用程序启动时异步“加热”您的 dbcontexts 来规避此问题。

protected void Application_Start()
 {
   // your code.
    // Warming up.
            Start(() =>
            {
                using (var dbContext = new SomeDbContext())
                { 
                    // Any request to db in current dbContext.
                    var response1 = dbContext.Addresses.Count();
                }
            });
 }

 private void Start(Action a)
 {
    a.BeginInvoke(null, null);
 }

我还建议使用以下设置:(如果它们适合您的应用)

  • dbContext.Configuration.AutoDetectChangesEnabled = 假; dbContext.Configuration.LazyLoadingEnabled = false; dbContext.Configuration.ProxyCreationEnabled = false;

  • 跳过验证部分(即Database.SetInitializer&lt;SomeDbContext&gt;(null);

  • 在 GET 查询中使用 .asNoTraking()

有关更多信息,您可以阅读:

【讨论】:

    【解决方案4】:

    在某些情况下,EF 不使用查询计划缓存。例如,如果您在查询中使用 contans、any、all 方法或使用常量。你可以试试NihFix.EfQueryCacheOptimizer。它将您的查询表达式转换为允许 EF 使用 cahce。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多