我一直在关注 Entity Framework 的性能,尤其是 Includes 的使用以及生成和执行各种查询所花费的时间。
我将详细说明我所做的更改,但如果您认为这些假设有任何错误,请纠正我。
首先,我们在一个数据库中有大约 10,000 个项目(不多),并且数据库已显着规范化(这导致了大量的导航属性)。目前的做法是延迟加载所有内容,考虑到请求一个项目可以分流出数十个 DB 请求,性能非常差,尤其是对于较大的数据集。 (这是一个继承项目,第一步是尝试在不进行重大重组的情况下提高性能)
因此,我的第一步是获取查询结果,然后仅将导航属性的 Includes 应用于这些结果。 我知道这在技术上执行了 2 个查询,但如果我们存储了 10,000 个项目,但只想返回 10 个项目,那么只包含这 10 个项目的导航属性更有意义。
其次,在查询结果上使用了多个包含并且结果集大小非常大的情况下,它仍然存在性能不佳的问题。对于何时进行急切加载以及何时保留延迟加载,我一直很务实。 我的下一个更改是批量加载查询包含,因此执行:
query.Include(q => q.MyInclude).Load();
这再次显着提高了性能,尽管多了几次 DB 调用(每批包含一次)它比大型查询更快,或者至少减少了 Entity Framework 尝试生成该大型查询的开销。
所以代码现在看起来像这样:
var query = ctx.Filters.Where(x => x.SessionId == id)
.Join(ctx.Items, i => i.ItemId, fs => fs.Id, (f, fs) => fs);
query
.Include(x => x.ItemNav1)
.Include(x => x.ItemNav2).Load();
query
.Include(x => x.ItemNav3)
.Include(x => x.ItemNav4).Load();
query
.Include(x => x.ItemNav5)
.Include(x => x.ItemNav6).Load();
现在,这是合理的性能,但是,进一步改进它会很好。
我曾考虑过使用 LoadAsync(),经过更多的重构后,它是可能的,并且会更好地适应架构的其余部分。
但是,您一次只能在数据库上下文中执行一个查询。所以我想知道是否有任何方法可以创建新的数据库上下文,对每组导航属性执行 LoadAsync()(异步),然后连接所有结果。
从技术上讲,我知道如何创建新的上下文,为每个导航组触发 LoadAsync(),但不知道如何连接结果,我不知道这是否绝对可行或者它是否违反了良好做法。
所以我的问题是;这是可能的,还是有另一种方法可以进一步提高性能?我试图坚持使用 Entity Framework 提供的内容,而不是制作一些存储过程。谢谢
更新
关于性能差异,我看到在一个语句中使用所有包含和在小组中加载它们之间。运行返回 6000 个项目的查询时。 (使用 SQL 事件探查器和 VS 诊断来确定时间)
分组包含:执行包含总共需要大约 8 秒。
在一条语句中包含:SQL 查询加载需要约 30 秒。 (经常超时)
经过更多调查后,我认为 EF 将 SQL 结果转换为模型时没有太多开销。然而,我们已经看到 EF 花费了将近 500 毫秒来生成复杂的查询,这并不理想,但我不确定这是否可以解决
更新 2
在 Ivan 的帮助下并遵循此 https://msdn.microsoft.com/en-gb/data/hh949853.aspx我们能够进一步改进,特别是使用 SelectMany。我会向任何试图提高其 EF 性能的人强烈推荐这篇 MSDN 文章。
最佳答案
您的第二种方法依赖于 EF 导航属性修复过程。问题是每一个
query.Include(q => q.ItemNavN).Load();
声明还将包括所有主记录数据以及相关实体数据。
使用相同的基本思想,一个潜在的改进可能是为每个导航属性执行一个 Load,将 Include 替换为 Select (用于引用)或 SelectMany(用于集合)- 类似于 EF Core 在内部处理 Include 的方式。
以您的第二种方法为例,您可以尝试以下方法并比较性能:
var query = ctx.Filters.Where(x => x.SessionId == id)
.Join(ctx.Items, i => i.ItemId, fs => fs.Id, (f, fs) => fs);
query.Select(x => x.ItemNav1).Load();
query.Select(x => x.ItemNav2).Load();
query.Select(x => x.ItemNav3).Load();
query.Select(x => x.ItemNav4).Load();
query.Select(x => x.ItemNav5).Load();
query.Select(x => x.ItemNav6).Load();
var result = query.ToList();
// here all the navigation properties should be populated
关于c# - Entity Framework 包括性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40155092/
如何在ruby中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL
我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha
C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.
我正在使用Ruby解决一些ProjectEuler问题,特别是这里我要讨论的问题25(Fibonacci数列中包含1000位数字的第一项的索引是多少?)。起初,我使用的是Ruby2.2.3,我将问题编码为:number=3a=1b=2whileb.to_s.length但后来我发现2.4.2版本有一个名为digits的方法,这正是我需要的。我转换为代码:whileb.digits.length当我比较这两种方法时,digits慢得多。时间./025/problem025.rb0.13s用户0.02s系统80%cpu0.190总计./025/problem025.rb2.19s用户0.0
我想编写一个ruby脚本来递归复制目录结构,但排除某些文件类型。因此,给定以下目录结构:folder1folder2file1.txtfile2.txtfile3.csfile4.htmlfolder2folder3file4.dll我想复制这个结构,但不包含.txt和.cs文件。因此,生成的目录结构应如下所示:folder1folder2file4.htmlfolder2folder3file4.dll 最佳答案 您可以使用查找模块。这是一个代码片段:require"find"ignored_extensions=[".cs"
我正在寻找一个用ruby演示计时器的在线示例,并发现了下面的代码。它按预期工作,但这个简单的程序使用30Mo内存(如Windows任务管理器中所示)和太多CPU有意义吗?非常感谢deftime_blockstart_time=Time.nowThread.new{yield}Time.now-start_timeenddefrepeat_every(seconds)whiletruedotime_spent=time_block{yield}#Tohandle-vesleepinteravalsleep(seconds-time_spent)iftime_spent
如果用户是所有者,我有一个条件来检查说删除和文章。delete_articleifuser.owner?另一种方式是user.owner?&&delete_article选择它有什么好处还是它只是一种写作风格 最佳答案 性能不太可能成为该声明的问题。第一个要好得多-它更容易阅读。您future的自己和其他将开始编写代码的人会为此感谢您。 关于ruby-on-rails-如果条件与&&,是否有任何性能提升,我们在StackOverflow上找到一个类似的问题:
我想写一点“Deprecate-It”库并经常使用“method_added”回调。但是现在我注意到在包含模块时不会触发此回调。是否有任何回调或变通方法,以便在某些内容包含到自身时通知类“Foobar”?用于演示的小Demo:#IncludingModulswon'ttriggermethod_addedcallbackmoduleInvisibleMethoddefinvisible"Youwon'tgetacallbackfromme"endendclassFoobardefself.method_added(m)puts"InstanceMethod:'#{m}'addedto'
我有一个正则表达式来获取"*"之间的所有内容:str="Donecsedodiodui.*Nullamiddoloridnibhultriciesvehiculaut*"str.match(/\*(.*)\*/)[1]我希望匹配能够包含换行符。我该怎么做? 最佳答案 您需要使用允许点匹配新行的m选项:Donecsedodiodui.*Nullamiddoloridnibhultriciesvehiculaut*regexstr.match(/\*(.*)\*/m)[1]实例:http://www.rubular.com/r/11u9
我如何做Ruby方法"Flatten"RubyMethod在C#中。此方法将锯齿状数组展平为一维数组。例如:s=[1,2,3]#=>[1,2,3]t=[4,5,6,[7,8]]#=>[4,5,6,[7,8]]a=[s,t,9,10]#=>[[1,2,3],[4,5,6,[7,8]],9,10]a.flatten#=>[1,2,3,4,5,6,7,8,9,10 最佳答案 递归解决方案:IEnumerableFlatten(IEnumerablearray){foreach(variteminarray){if(itemisIEnume