我有一个ASP.NET核心3网站,经常耗尽内存上的Azure。
其中一个繁重(但经常使用)的函数是生成报告。所以我想我应该用一个这样的报告作为测试用例来看看到底发生了什么。
以下是应用程序加载后的内存快照,然后是对其中一个报表的9个后续请求之后的快照。
从诊断的角度看,EF更改跟踪对象占用了大量内存。
我发现,如果在启动时使用options.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
,那么相同活动的快照将产生以下结果:
这是一个巨大的改进-为每个请求添加2MB是不可行的。这是正常的-我会想,即使改变跟踪,GC不会让它变得如此糟糕?或者,我的报告代码中可能有什么东西使其保持引用或其他东西--我读到了类中的静态变量可能导致GC不释放这些实例,这是可能的吗?我不确定关闭某些默认功能是否仅仅是对其他我正在做的根本错误的事情的创可贴(我很确定我正在用using
语句来处理所有的东西,等等)。
发布于 2021-01-19 12:48:31
我想说的是,当将所有EF查询切换为NoTracking
时,尤其是在报告最有可能读取的场景中,然后跟踪内存中的大量对象时,就会出现这样的结果。
在官方文件中,您可以找到有关此主题的详细信息。在这里,您还可以看到一个比较两个查询性能的基准,一个使用更改跟踪器,另一个没有使用一个小数据集(10个博客,每个博客有20个帖子)。尽管数据量很小,但结果与您的相似:性能几乎提高了40%,分配的内存减少了几乎40%。
因此,关于I'm not sure if switching off some default functionality is just a band-aid to something else I'm doing fundamentally wrong
,我肯定地说,这根本不是一个创可贴解决方案,只是为了报告功能。在这些需要提高性能的只读场景中,实际上建议使用非跟踪查询。
但是,我唯一知道的是,您可能不希望对应用程序中的所有查询关闭跟踪行为。通过这样做,如果您依赖变更跟踪器对应用程序中其他地方的实体执行更新,则这些更新将停止工作。
例如:
var blog = context.Blogs
.Where(blog => blog.Id = blogId)
.SingleOrDeafult();
blog.Name = "Another Name";
context.SaveChanges() // If the default query behaviour is 'NoTracking', the Blog's name won't be updated since it wasn't in the ChangeTracker.
相反,我要做的是将默认行为保持为跟踪,但随后我将将仅在reports中使用的所有查询更改为非跟踪方式。要实现这一点,您必须在所有reporting查询中添加.AsNoTracking()
。
例如:
var blogs = context.Blogs
.AsNoTracking()
.ToList();
这样,您将大大提高只读查询的性能,而不会影响其他应用程序行为。
https://stackoverflow.com/questions/65747698
复制相似问题