Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/264.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 实体框架5性能问题_C#_Sql_Asp.net Mvc_Performance_Entity Framework - Fatal编程技术网

C# 实体框架5性能问题

C# 实体框架5性能问题,c#,sql,asp.net-mvc,performance,entity-framework,C#,Sql,Asp.net Mvc,Performance,Entity Framework,现在我正在处理一个相当复杂的数据库。我们的对象模型被设计为映射到数据库。我们将EF5用于手动生成的POCO类 一切正常,但也有人对表演不满。我从来没有遇到过EF的性能问题,所以我想知道这一次我是做错了什么,还是这个问题可能存在于其他地方 主查询可以由动态参数组成。我有几个if和switch块,它们在概念上是这样的: if (parameter != null) { query = query.Where(c => c.Field == parameter); } 另外,对于一些复杂和/或

现在我正在处理一个相当复杂的数据库。我们的对象模型被设计为映射到数据库。我们将EF5用于手动生成的POCO类

一切正常,但也有人对表演不满。我从来没有遇到过EF的性能问题,所以我想知道这一次我是做错了什么,还是这个问题可能存在于其他地方

主查询可以由动态参数组成。我有几个if和switch块,它们在概念上是这样的:

if (parameter != null) { query = query.Where(c => c.Field == parameter); }
另外,对于一些复杂和/或组合,我使用Albahari的LinqKit扩展

该查询针对的是一个大的“订单”表,其中包含了一年又一年的数据。不过,平均使用时间为2个月

现在,当主查询组成时,将使用
Skip/Take
组合对其进行分页,其中Take设置为10个元素

在所有这些之后,IQueryable通过层发送,到达使用Automapper的MVC层

在这里,当Automapper开始迭代时(从而真正执行查询),它会调用一组导航属性,这些属性有自己的导航属性等等。根据EF建议,所有内容都设置为延迟加载,以避免在包含3或4个以上不同实体的情况下急于加载。我的场景是这样的:

if (parameter != null) { query = query.Where(c => c.Field == parameter); }
  • 订单(最多10个)
    • 许多导航属性都已订购
      • 其中一些下有其他导航(本地化实体)
    • 订单详细信息(每个订单有多个订单详细信息)
      • 每个订单详细信息下的许多导航属性
        • 其中一些下有其他导航(本地化实体)
这很容易导致单个呈现的“页面”总共有300多个查询。这些查询中的每一个都非常快,运行时间为几毫秒,但仍有两个主要问题:

  • 延迟加载的属性是按顺序调用的,而不是并行化的,因此需要更多的时间
  • 作为前一点的结果,每个查询之间都有一些死时间,因为数据库必须为每个查询接收sql、运行sql、返回sql等等
为了看看它是如何进行的,我尝试用急切的加载进行相同的查询,正如我预测的那样,这是一场彻底的灾难,翻译的sql超过7K行(是的,7000行),总体速度要慢得多

现在我不愿意认为EF和Linq不是这种情况下的正确选择。有些人说,如果他们编写一个存储过程来获取所有需要的数据,那么它的运行速度会快几十倍。我不相信这是真的,我们将失去所有相关实体的自动物化

我想到了一些可以改进的事情,比如:

  • 表拆分以减少所选列
  • 关闭对象跟踪,因为此场景为只读(具有未跟踪的实体)
尽管如此,主要的抱怨是结果页面(在MVC4中完成)呈现得太慢,经过一点诊断后,它似乎都是“服务器时间”,而不是“网络时间”,大约需要8到12秒的服务器时间

根据我的经验,这不应该发生。我想知道我是否以错误的方式处理了这个查询需求,或者我是否必须将注意力转向其他方面(可能是配置不好的IIS服务器,或者其他我真的不知道的东西)。也就是说,数据库的索引还可以,由我们的dba非常仔细地检查


所以,如果任何人有任何提示、建议、最佳实践,我都不知道,或者可以告诉我,在这个场景中使用EF和延迟加载是大错特错的。。。大家都欢迎。

考虑一下,EF肯定有助于使开发时间更快。但是,您必须记住,当您从数据库返回大量数据时,EF使用的是动态SQL。这意味着EF必须为1。创建SQL,2.SQL Server然后需要创建一个执行计划。这发生在查询运行之前


在使用存储过程时,SQL Server可以缓存执行计划(可以对其进行编辑以提高性能),这确实比使用EF更快。但是您始终可以创建存储过程,然后从EF执行它。我会将任何复杂的过程或查询转换为存储过程,然后从EF调用。然后,您可以看到您的性能提高,并从中重新评估。

试着想出一个高效而简单的sql查询来获取视图的数据

有可能吗

如果没有,请尝试对表进行分解(反规范化),以减少获取数据所需的联接。此外,表列上是否有有效的索引以加快数据检索

如果是,请忘记EF,编写一个存储过程并使用它获取数据

对于只读方案,必须关闭所选查询的跟踪。看看我的数字:

正如您所看到的,跟踪和不跟踪场景之间的差异是显著的


我会尝试快速加载,但不是在所有地方(这样你就不会得到7k行长的查询),而是在选定的子查询中。

对于一个产生大量分层数据的非常复杂的查询,如果你采取正确的方法,存储过程通常不会比LINQ/EF更好地提高性能。正如您所注意到的,EF(惰性和急切加载)的两个“开箱即用”选项在这种情况下不能很好地工作。但是,仍然有几种很好的方法可以优化此功能:

(1) 与其将一组实体读入内存,然后通过automapper进行映射,不如尽可能直接在查询中进行“自动映射”。例如:

var mapped = myOrdersQuery.Select(o => new OrderInfo { Order = o, DetailCount = o.Details.Count, ... })
    // by deferring the load until here, we can bring only the information we actually need 
    // into memory with a single query
    .ToList();
// read with AsNoTracking() since we'll be manually setting associations
var myOrders = myOrdersQuery.AsNoTracking().ToList();
var orderIds = myOrders.Select(o => o.Id);
var myDetails = context.Details.Where(d => orderIds.Contains(d.OrderId)).ToLookup(d => d.OrderId);
// reassemble in memory
myOrders.ForEach(o => o.Details = myDetails[o.Id].ToList());
如果您只需要复杂层次结构中字段的子集,那么这种方法非常有效。此外,EF选择hierarchica的能力