我一直在关注Entity Framework的性能,特别是关于使用Includes以及生成和执行各种查询所花费的时间.
我将详细介绍我所做的更改,但如果您认为任何这些假设是错误的,请纠正我.
首先,我们在数据库中有大约10,000个项目(不是很多),并且数据库显着标准化(这导致了大量的导航属性).目前的方法是延迟加载所有内容,并且假设请求一个项目可以假脱机数十个db请求,性能非常差,特别是对于较大的数据集.(这是一个继承的项目,第一步是尝试在没有重大重组的情况下提高性能)
因此,我的第一步是获取查询结果,然后仅将导航属性的包含应用于这些结果.我知道这在技术上执行了2个查询,但如果我们存储了10,000个项目,但只想返回10个项目,那么仅在这10个项目中包含导航属性更有意义.
其次,在查询结果上使用多个包含且结果集大小非常大的情况下,它仍然会遇到性能不佳的问题.我一直在务实关于什么时候需要加载以及何时将延迟加载到位.我的下一个更改是批量加载查询包含,因此执行:
query.Include(q => q.MyInclude).Load();
这再一次显着提高了性能,虽然还有一些db调用(每批包含一个),它比大型查询更快,或者至少减少了实体框架尝试生成大型查询的开销.
所以代码现在看起来像这样:
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();
Run Code Online (Sandbox Code Playgroud)
现在这是相当高效的,但是,进一步改进这一点会很好.
我曾经考虑过使用LoadAsync(),经过一些重构后,它可以更好地适应架构的其他部分.
但是,您只能在db上下文中一次执行一个查询.所以我想知道是否有可能创建一个新的db上下文,LoadAsync()对每组导航属性执行(异步)然后连接所有结果.
我从技术上知道你如何创建一个新的上下文,LoadAsync()为每个导航组启动一个,但不是如何连接结果,我不知道它是否有可能或者是否违反了良好的做法.
所以我的问题是; 这是可能的,还是有另一种方法可以进一步提高性能吗?我试图坚持实体框架提供的东西,而不是制作一些存储过程.谢谢
UPDATE
关于在一个语句中使用所有包含和在小组中加载这些包含之间的性能差异.运行返回6000个项目的查询时.(使用SQL事件探查器和VS诊断程序确定时间)
分组包括:执行包含总共需要约8秒.
包含在一个语句中:SQL查询需要大约30秒才能加载.(通常会超时)
经过一番调查后,我不认为当EF将sql结果转换为模型时会有很多开销.但是我们已经看到EF用于生成复杂查询的近500毫秒,这不是理想的,但我不确定这是否可以解决
更新2
在Ivan的帮助下,通过这个https://msdn.microsoft.com/en-gb/data/hh949853.aspx,我们能够进一步改进,特别是使用SelectMany.我强烈推荐msdn文章给任何试图改善其EF性能的人.
我正在使用Redux,我正在尝试使我的减速器类型安全.我在ngrx-store/example应用程序中找到了一些代码示例,他们完全成功地做到了这一点.(https://github.com/ngrx/example-app/blob/master/src/app/actions/book.ts)
在将这个集成到我自己的项目中时,我发现了一些奇怪的东西,我无法解释.检查以下代码示例(内联注释):
// Action has a type and payload property
interface Action {
type: string;
payload?: any;
}
// Here I declare the action types as plain strings
const FIRST = "FIRST";
const SECOND = "SECOND";
// I create classes for every action with there respective types
class FirstAction implements Action {
public type = FIRST;
payload: { id: number };
public constructor(id: number) {
this.payload = { id };
}
}
class SecondAction implements Action {
public …Run Code Online (Sandbox Code Playgroud)