LINQ性能中的EF-Core方法调用

时间:2017-08-01 11:51:30

标签: c# entity-framework linq entity-framework-core

这个问题不是关于entityframework本身的异步问题,如讨论here

在方法CalculateSomething中,您可以看到两个LINQ调用。 第一个LINQ-Call(初始化result)的性能绝对没问题。

然而,第二个LINQ-Call(初始化resultWithDate)的性能比第一个慢。

第一个需要2秒,第二个需要15-20秒。

dataBase是我的DbContext课程。我使用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;
  }

问题不在于方法调用IsOlderThan30Days,问题在于CountAsync。我知道这是因为我有这样的事情:

  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;
  }

两次CountAsync()来电时出现了性能损失。 CountAsync resultWithDateCount上的CountAsync花费了15秒,而resultCount result只花了2秒钟。初始化resultWithDateselect to_char(sysdate,'day') from dual同样快。

我做错了吗?

谢谢

3 个答案:

答案 0 :(得分:3)

试试这个:

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;

或者:

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);

关键是尝试在LINQ的进行30天的日期计算。

答案 1 :(得分:1)

好的,这是一段来自@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;
}

答案 2 :(得分:1)

问题是IsOlderThan30Days强制将数据加载到内存中。您应该能够通过在数据库中进行计算来获得一些性能:

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)
     );