优化实体框架查询当我有50-60个问题时一切正常,我使用RedGate数据生成器并尝试将其增加到100万个问题,几千个子表行并不重要只是为了稍微“强调”ORM。这就是linq的样子varquery=ctx.Questions.AsNoTracking()//只读性能提升..http://visualstudiomagazine.com/articles/2010/06/24/five-tips-linq-to-sql.aspx.Include("Attachments").Include("Location").Include("CreatedBy")//IdentityUser.Include("Tags").Include("Upvotes").Include("Upvotes.CreatedBy").Include("Downvotes").Include("Downvotes.CreatedBy").AsQueryable();if(string.IsNullOrEmpty(sort))//默认{query=query.OrderByDescending(x=>x.CreatedDate);}else{sort=sort.ToLower();if(sort=="latest"){query=query.OrderByDescending(x=>x.CreatedDate);}elseif(sort=="popular"){//查看次数最多的query=query.OrderByDescending(x=>x.ViewCount);}}varcomplaints=query.Skip(skipCount).Take(pageSize).ToList();//makesanevaluation..不用说,我得到了SQL超时,并且在安装Miniprofiler之后,查看生成的sql语句,它有可怕的几百行。我知道我正在加入/包含太多表,但在现实生活中我们只需要加入1或2个表有多少项?可能会有这样的情况,我们必须对数百万行进行如此多的连接,是唯一的存储过程吗?如果是这样,EF本身是否只适用于小型项目?您遇到的问题很可能是笛卡尔积。仅基于一些示例数据:varquery=ctx.Questions//50.Include("Attachments")//20.Include("Location")//10.Include("CreatedBy")//5.Include("标签")//5.Include("Upvotes")//5.Include("Upvotes.CreatedBy")//5.Include("Downvotes")//5.Include("Downvotes.CreatedBy")//5//WhereBlah//OrderByBlah这将返回行数最多50x20x10x5x5x5x5x5x5=156,250,000说真的......这是要返回的INSANE行数。如果你遇到这个问题,你真的有两个选择:第一:最简单的方法,依靠实体框架在进入上下文时自动连接模型。然后,使用实体AsNoTracking()并处理上下文。//继续上面的查询:varquestions=query.选择(q=>q);var附件=查询。选择(q=>q。附件);变种位置=查询。选择(q=>q。位置);这将为每个表发出一个请求,但不会下载1.56亿行,而只会下载110行。但最酷的部分是它们都连接在EF上下文缓存内存中,所以现在问题变量已完全填充。第二步:创建一个返回多个表的存储过程,让EF实现该类。我没有看到您的LINQ查询有任何明显的错误(.AsQueryable()不应该是强制性的,但删除它不会改变任何东西)。当然,不要包含不必要的导航属性(每个都添加一个SQLJOIN),但如果一切都需要,那应该没问题。现在,当C#代码看起来不错时,是时候查看生成的SQL代码了。正如您所做的那样,第一步是检索已执行的SQL查询。有.Net方式,对于SQLServer,我个人总是启动SQLServer分析会话。有了SQL查询后,尝试直接对数据库执行它,不要忘记包括实际的执行计划。在大多数情况下,这将准确显示查询的哪一部分。它甚至会指出您是否有明显缺失的索引。现在的问题是,如果您添加所有这些索引,您的SQLServer会告诉您它们丢失了吗?不必要。例如,请参阅不要盲目地创建缺失索引。您必须选择应该添加哪些索引,哪些不应该添加。由于代码优先方法为您创建索引,我假设它们只是主键和外键的索引。这是一个好的开始,但这还不够。我不知道表中的行数,但只有您可以添加的明显索引(没有代码生成工具可以这样做,因为它与业务查询相关),例如CreatedDate列上的索引,因为您订购了商品通过这个值。如果不这样做,SQLServer将不得不对1M行执行表扫描,这在性能方面当然是灾难性的。所以:如您所知,Include方法会生成可怕的SQL。免责声明:我是EntityFrameworkPlus(EF+)项目的所有者EF+QueryIncludeOptimized方法允许优化生成的SQL,就像EFCore一样。生成多个SQL(每个一个)而不是一个可怕的SQL。另外作为奖励,此功能允许过滤相关实体。文档:EF+QueryIncludeOptimizedvarquery=ctx.Questions.AsNoTracking().IncludeOptimized(x=>x.Attachments).IncludeOptimized(x=>x.Location).IncludeOptimized(x=>x.CreatedBy)//IdentityUser。IncludeOptimized(x=>x.Tags).IncludeOptimized(x=>x.Upvotes).IncludeOptimized(x=>x.Upvotes.Select(y=>y.CreatedBy)).IncludeOptimized(x=>x.Downvotes)。IncludeOptimized(x=>x.Downvotes.Select(y=>y.CreatedBy)).AsQueryable();查看Microsoft文档的第8.2.2节:8.2.2多个包含的性能问题当我们听说服务器响应时间问题导致性能问题时,问题的根源通常是具有多个包含语句的查询。虽然在查询中包含相关实体非常强大,但了解幕后发生的事情也很重要。具有多个Include语句的查询需要相对较长的时间才能通过内部计划编译器生成存储命令。大部分时间都花在了优化结果查询上。生成的存储命令将包含每个Include的外部联接或联合,具体取决于您的映射。像这样的查询将在单个有效载荷中在数据库中引入一个大的连接图,这将消除任何带宽问题,尤其是在有效载荷中存在大量冗余的情况下(即包括多个级别的Include遍历其中一个关联-–多向)。您可以通过使用ToTraceString访问查询的基础TSQL并在SQLServerManagementStudio中执行存储命令来查看负载大小,从而检查查询是否返回过大负载的情况。在这种情况下,您可以尝试减少查询中的Include语句的数量,以便只引入您需要的数据。或者,您可以将查询分解为更小的子查询序列,例如:在分解查询之前:其中c.LastName.StartsWith(lastNameParameter)选择c;foreach(Customercustomerincustomers){...}}中断查询后:using(NorthwindEntitiescontext=newNorthwindEntities()){varorders=fromoincontext.o.Customer.LastName.StartsWith(lastNameParameter)选择o的订单;订单.Load();varcustomers=fromcincontext.Customerswherec.LastName.StartsWith(lastNameParameter)选择c;foreach(Customercustomerincustomers){...}}这仅适用于跟踪查询,因为我们正在利用上下文的能力自动进行身份解析和关联修复。与延迟加载一样,权衡将是对较小负载的更多查询。您还可以使用对单个属性的投影来显式选择每个实体所需的数据,但在这种情况下,您不会加载实体并且不支持更新。以上就是C#学习教程:优化实体框架查询分享的全部内容。如果对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:
