简体   繁体   English

LINQ性能中的EF核心方法调用

[英]EF-Core Method Call in LINQ Performance

this problem is not about async problems with entityframework itself as discussed here . 这个问题与这里讨论的实体框架本身的异步问题无关。

In the method CalculateSomething you can see two LINQ-Calls. CalculateSomething方法中,您可以看到两个LINQ调用。 The performance of the first LINQ-Call (initializing result ) is absolutely okay. 第一次LINQ-Call(初始化result )的性能绝对可以。

However, the performance of the second LINQ-Call (initializing resultWithDate ) Is way slower than the first one. 但是,第二个LINQ-Call(初始化resultWithDate )的性能比第一个慢。

The first one takes 2 Seconds, The second one takes 15-20 Seconds. 第一个花费2秒,第二个花费15-20秒。

dataBase is my DbContext class. dataBase是我的DbContext类。 Iam using Entity Framework Core. 我使用实体框架核心。

  private async Task<long> CalculateSomething(string numberOne, MyStatus status)
  {
     var result = await this.dataBase.Something.CountAsync(item => item.NumberOne== numberOne && item.Status == (short)status);
     var resultWithDate = await this.dataBase.Something.CountAsync(item => item.NumberOne== numberOne && item.Status == (short)status && !this.IsOlderThan30Days(item.Date));

     return result;
  }

  private bool IsOlderThan30Days(DateTime? itemDate)
  {
     bool result = true;

     if (itemDate.HasValue) 
     {
        if ((DateTime.Now - itemDate.Value).TotalDays <= 30)
        {
           result = false;
        }
     }

     return result;
  }

The problem is not the method call IsOlderThan30Days , the problem is about CountAsync . 问题不在于方法调用IsOlderThan30Days ,而是与CountAsync有关。 I know this because I had something like this: 我知道这是因为我有这样的事情:

  private async Task<long> CalculateAmountOfOrders(string numberOne, MyStatus status)
  {
     var result = this.dataBase.Something.Where(item => item.NumberOne == numberOne && item.Status == (short)status);
     var resultWithDate = this.dataBase.Something.Where(item => item.NumberOne == numberOne && item.Status == (short)status && !this.IsOlderThan30Days(item.Date));

     var resultCount = await result.CountAsync();
     var resultWithDateCount = await resultWithDate.CountAsync();

     return resultCount;
  }

And the performance loss appeared at the two CountAsync() calls. 并且性能损失出现在两个CountAsync()调用中。 CountAsync on resultWithDateCount took 15 seconds while CountAsync on resultCount only took 2 seconds. CountAsyncresultWithDateCount花了15秒,而CountAsyncresultCount只用了2秒。 initializing result and resultWithDate was equally fast. 初始化resultresultWithDate速度同样快。

Am I doing something wrong? 难道我做错了什么?

Thank you 谢谢

Try this: 尝试这个:

var date = DateTime.Now.AddDays(-30);
var result = await this.dataBase.Something.CountAsync(item => item.NumberOne == numberOne && item.Status == (short)status);
var resultWithDate = itemDate.HasValue ? await this.dataBase.Orders.CountAsync(item => item.NumberOne == numberOne && item.Status == (short)status && 
        itemDate.Value < date) : 0;

Or alternatively: 或者:

var date = DateTime.Now.AddDays(-30);
var result = await this.dataBase.Something.CountAsync(item => item.NumberOne == numberOne && item.Status == (short)status);
var resultWithDate = await this.dataBase.Orders.CountAsync(item => item.NumberOne == numberOne && item.Status == (short)status && 
        itemDate < date);

The key is trying to do the 30 day date calculation outside of the LINQ. 关键是试图在LINQ 之外进行30天日期计算。

Ok here is a code inspired from @mjwills : 好的,这是一个受@mjwills启发的代码:

private async Task<long> CalculateSomething(string numberOne, MyStatus status)
{
  var date = DateTime.Now.AddDays(-30);

  var result = await this.dataBase.Something.CountAsync(item => 
  item.NumberOne == numberOne && item.Status == (short)status);
  var resultWithDate = await this.dataBase
    .Something
    .CountAsync(item => item.NumberOne == numberOne && item.Status == (short)status && (!item.Date.HasValue  || item.Date.Value <= date));

  return result;
}

The problem is that IsOlderThan30Days forces loading data into memory. 问题是IsOlderThan30Days强制将数据加载到内存中。 You should be able to gain some performance by doing the computation in the database: 您应该能够通过在数据库中进行计算来获得一些性能:

var now = DateTime.Now;
var resultWithDate = await this.dataBase
     .Something
     .CountAsync(item =>
         item.NumberOne== numberOne
     &&  item.Status == (short)status
     &&  (item.Date != null && EntityFunctions.DiffDays(item.Date, now) <= 30)
     );

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

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