简体   繁体   English

EF Core Complex 查询会针对参数的每个变化进行缓存

[英]EF Core Complex query gets cached for each variation of parameters

I have a complex query that seems to cause a memory leak in my applications memory.我有一个复杂的查询,它似乎导致我的应用程序内存中出现内存泄漏。

From my understanding the query result is cached so that this processing does not need to be done every time the query is executed.根据我的理解,查询结果是缓存的,因此不需要每次执行查询时都进行此处理。 https://docs.microsoft.com/en-us/ef/core/querying/how-query-works https://docs.microsoft.com/en-us/ef/core/querying/how-query-works

But what it looks like is that the query is getting cached for each and every user that logs into the system.但是看起来查询正在为每个登录系统的用户缓存。 From the memory dump it looks like we have thousands of compiled query cache objects for the same query.从内存转储看来,我们有数千个已编译的查询缓存对象用于同一查询。

在此处输入代码 在此处输入图片说明

The query looks as follows.查询如下所示。

public async Task<IList<EmployeeInboxMessage>> GetEmployeeMessagesAsync(long employeeId)
        {
            return await (from message in this.Repository.Set
                          join userStep in this.Repository.Context.Set<UserWorkflowHeaderStep>() on message.UserWorkflowStepId equals userStep.UserWorkflowStepId into userSteps
                          from userStep in userSteps.DefaultIfEmpty()
                          join acceptedStep in this.Repository.Context.Set<CompanyWorkflowStep>() on userStep.AcceptedStepId equals acceptedStep.WorkflowStepId into acceptedSteps
                          from acceptedStep in acceptedSteps.DefaultIfEmpty()
                          join rejectedStep in this.Repository.Context.Set<CompanyWorkflowStep>() on userStep.RejectedStepId equals rejectedStep.WorkflowStepId into rejectedSteps
                          from rejectedStep in rejectedSteps.DefaultIfEmpty()

                          let step =
                              message.InboxEntryType == InboxEntryType.Claims ||
                              message.InboxEntryType == InboxEntryType.AdvancedLeave ||
                              message.InboxEntryType == InboxEntryType.ChangeRequest
                                  ? new WorkflowHeaderStep
                                  {
                                      WorkflowItem = userStep.WorkflowItem,
                                      AcceptedStepId = userStep.AcceptedStepId,
                                      AcceptedStep = acceptedStep == null ? null : new WorkflowStep
                                      {
                                          OnApprovalActionId = acceptedStep.OnApprovalActionId,
                                          OnRejectionAction = acceptedStep.OnRejectionAction,
                                          OrderNumber = acceptedStep.OrderNumber
                                      },
                                      RejectedStepId = userStep.RejectedStepId,
                                      RejectedStep = rejectedStep == null ? null : new WorkflowStep
                                      {
                                          OnApprovalActionId = rejectedStep.OnApprovalActionId,
                                          OnRejectionAction = rejectedStep.OnRejectionAction,
                                          OrderNumber = rejectedStep.OrderNumber
                                      }
                                  }
                                  : null

                          let employeeName = string.IsNullOrWhiteSpace(message.OBOEmployee.PreferredName)
                              ? message.OBOEmployee.FullName
                              : message.OBOEmployee.PreferredName + " " + message.OBOEmployee.LastName

                          where message.EmployeeId == employeeId
                          orderby message.EffectiveDate
                          select new EmployeeInboxMessage
                          {
                              Message = message,
                              UserStep = step,
                              UserId = message.UserId,
                              UserName = message.User.FullName,
                              EmployeeName = message.OBOEmployeeId.HasValue
                                  ? employeeName
                                  : message.User.FullName,
                              RelatedPrimaryKey =
                                  message.InboxEntryType == InboxEntryType.Claims ||
                                  message.InboxEntryType == InboxEntryType.AdvancedLeave ||
                                  message.InboxEntryType == InboxEntryType.ChangeRequest
                                      ? userStep.RelatedPrimaryKey
                                      : message.UserWorkflowStepId!.Value,
                              StartUserCompanyId = message.StartUser.CompanyId
                          }).ToListAsync();
        }

It looks like your query is to complex for EF to create a single CompiledQueryCache object and it is adding a cached version for each "employeeId" that you are passing in. By the looks of it there is already 27804 versions.看起来您的查询对于 EF 创建单个 CompiledQueryCache 对象来说很复杂,并且它正在为您传入的每个“employeeId”添加一个缓存版本。从它的外观来看,已经有 27804 个版本。

If you restructure your query then it might solve your problem.如果您重组您的查询,那么它可能会解决您的问题。 Try removing the "let step = ..." and "let employeeName = ...".尝试删除“let step = ...”和“let employeeName = ...”。 Worst case you would need to create raw SQL or maybe a view.最坏的情况是您需要创建原始 SQL 或视图。

There is not a lot of documentation out there explaining how EF creates the query cache(I can't find any).没有很多文档解释 EF 如何创建查询缓存(我找不到任何)。 You might never now what exactly your problem is except if some of the EF creators give some input or you could always go through their code.您现在可能永远不会知道您的问题究竟是什么,除非某些 EF 创建者提供了一些输入,或者您可以随时查看他们的代码。

If you still have a problem after changing your query it might be best to log a issue with efcore https://github.com/dotnet/efcore如果更改查询后仍有问题,最好使用 efcore https://github.com/dotnet/efcore记录问题

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM