实体框架性能缓慢

4
我们使用的是EF 6.0,.NET 4.5并使用Code First方法。我们的数据库大约有170个实体(表),其中主表包含大约150,000条记录。在第一次加载实体框架时,需要大约25秒的时间。由于记录数的增加会导致速度变慢,因此我正在尝试改进这个时间。我已经尝试生成本地映像,并尝试使用预生成的交互式视图,但没有取得任何显著的改进。请问是否有人可以帮助我解决这个问题呢?谢谢。

确保启用了延迟加载。 - asdf_enel_hak
你真的需要从代码中使用所有170个表吗? - ErikEJ
你能展示一个执行时间较长的查询示例吗? - Vlad274
如果您不关心自动跟踪,请使用 .AsNoTacking()。 - magicandre1981
@magicandre1981 已经做过了,没有帮助。 - siddhanntarora
显示剩余5条评论
4个回答

2
您可以考虑使用Entity Framework预生成的映射视图。您可以使用EF Power Tools来创建预生成的视图。

使用预生成的视图将视图生成的成本从模型加载(运行时)移动到编译时。虽然这可以提高运行时的启动性能,但在开发过程中仍会遇到视图生成的痛点。有一些额外的技巧可以帮助减少视图生成的成本,无论是在编译时还是运行时。

enter image description here

您可以参考此链接了解更多信息:Entity Framework预生成的映射视图

您可以使用Entity Framework缓存来提高应用程序的性能。

有三种类型的缓存:

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

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

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

您可以参考此文章了解更多信息:EF 6的性能考虑


1
我已经尝试使用预生成的视图,但没有帮助。将尝试缓存选项。 - siddhanntarora

2
您也可以在应用程序启动时异步“预热”您的数据库上下文,以规避此问题。
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 = false; dbContext.Configuration.LazyLoadingEnabled = false; dbContext.Configuration.ProxyCreationEnabled = false;

  • 跳过验证部分(即Database.SetInitializer<SomeDbContext>(null);

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

如需更多信息,请阅读:


2
我最近遇到了一个简单的查询,在SSMS中运行非常快,但在C#程序中使用Entity Framework运行却需要太长时间。这个页面对于排除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);
                }
            }
        }
< p >(对于这个特定的查询,我完全绕过了EF,使用了旧有的可靠工具:System.Data.SqlClient。)< /p > < p >你可能会皱起鼻子感到厌恶;我当然也是 - 但实际上编写它并不需要太长时间,并且执行几乎瞬间完成。< /p >

1
“皱起我的鼻子”?!这太聪明了。+1 使用EF作为主流,当有意义的时候在异常情况下分歧。这是约定优于配置的绝佳例证。 - Rap

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接